mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Implement correct ForumTopic::canWrite logic.
This commit is contained in:
parent
1cd02fc3c9
commit
602ba5bba9
35 changed files with 363 additions and 144 deletions
|
@ -513,6 +513,12 @@ void ApiWrap::sendMessageFail(
|
||||||
Assert(randomId != 0);
|
Assert(randomId != 0);
|
||||||
_session->data().unregisterMessageRandomId(randomId);
|
_session->data().unregisterMessageRandomId(randomId);
|
||||||
item->sendFailed();
|
item->sendFailed();
|
||||||
|
|
||||||
|
if (error == u"TOPIC_CLOSED"_q) {
|
||||||
|
if (const auto topic = item->topic()) {
|
||||||
|
topic->setClosed(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3005,7 +3011,10 @@ void ApiWrap::finishForwarding(const SendAction &action) {
|
||||||
if (!toForward.items.empty()) {
|
if (!toForward.items.empty()) {
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
history->peer,
|
history->peer,
|
||||||
toForward.items);
|
{
|
||||||
|
.topicRootId = action.topicRootId,
|
||||||
|
.forward = &toForward.items,
|
||||||
|
});
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3074,6 +3083,9 @@ void ApiWrap::forwardMessages(
|
||||||
if (sendAs) {
|
if (sendAs) {
|
||||||
sendFlags |= MTPmessages_ForwardMessages::Flag::f_send_as;
|
sendFlags |= MTPmessages_ForwardMessages::Flag::f_send_as;
|
||||||
}
|
}
|
||||||
|
if (action.topicRootId) {
|
||||||
|
sendFlags |= MTPmessages_ForwardMessages::Flag::f_top_msg_id;
|
||||||
|
}
|
||||||
|
|
||||||
auto forwardFrom = draft.items.front()->history()->peer;
|
auto forwardFrom = draft.items.front()->history()->peer;
|
||||||
auto ids = QVector<MTPint>();
|
auto ids = QVector<MTPint>();
|
||||||
|
@ -3093,7 +3105,7 @@ void ApiWrap::forwardMessages(
|
||||||
MTP_vector<MTPint>(ids),
|
MTP_vector<MTPint>(ids),
|
||||||
MTP_vector<MTPlong>(randomIds),
|
MTP_vector<MTPlong>(randomIds),
|
||||||
peer->input,
|
peer->input,
|
||||||
MTPint(), // top_msg_id
|
MTP_int(action.topicRootId),
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||||
)).done([=](const MTPUpdates &result) {
|
)).done([=](const MTPUpdates &result) {
|
||||||
|
@ -3145,7 +3157,7 @@ void ApiWrap::forwardMessages(
|
||||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||||
messageFromId,
|
messageFromId,
|
||||||
messagePostAuthor,
|
messagePostAuthor,
|
||||||
item);
|
item); // #TODO forum forward
|
||||||
_session->data().registerMessageRandomId(randomId, newId);
|
_session->data().registerMessageRandomId(randomId, newId);
|
||||||
if (!localIds) {
|
if (!localIds) {
|
||||||
localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
|
localIds = std::make_shared<base::flat_map<uint64, FullMsgId>>();
|
||||||
|
@ -3405,7 +3417,13 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
||||||
action.generateLocal = true;
|
action.generateLocal = true;
|
||||||
sendAction(action);
|
sendAction(action);
|
||||||
|
|
||||||
if (!peer->canWrite() || Api::SendDice(message)) {
|
const auto replyToId = message.action.replyTo;
|
||||||
|
const auto replyTo = replyToId
|
||||||
|
? peer->owner().message(peer, replyToId)
|
||||||
|
: nullptr;
|
||||||
|
const auto topic = replyTo ? replyTo->topic() : nullptr;
|
||||||
|
if (!(topic ? topic->canWrite() : peer->canWrite())
|
||||||
|
|| Api::SendDice(message)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
local().saveRecentSentHashtags(textWithTags.text);
|
local().saveRecentSentHashtags(textWithTags.text);
|
||||||
|
|
|
@ -342,7 +342,7 @@ auto AddBotToGroupBoxController::createRow(not_null<History*> history)
|
||||||
bool AddBotToGroupBoxController::needToCreateRow(
|
bool AddBotToGroupBoxController::needToCreateRow(
|
||||||
not_null<PeerData*> peer) const {
|
not_null<PeerData*> peer) const {
|
||||||
if (sharingBotGame()) {
|
if (sharingBotGame()) {
|
||||||
if (!peer->canWrite()
|
if (!peer->canWrite() // #TODO forum forward
|
||||||
|| peer->amRestricted(ChatRestriction::SendGames)) {
|
|| peer->amRestricted(ChatRestriction::SendGames)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1153,8 +1153,7 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox(
|
||||||
for (const auto peer : result) {
|
for (const auto peer : result) {
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
peer,
|
peer,
|
||||||
{},
|
{ .text = &comment });
|
||||||
comment);
|
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
return std::make_pair(error, peer);
|
return std::make_pair(error, peer);
|
||||||
}
|
}
|
||||||
|
@ -1205,7 +1204,7 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox(
|
||||||
auto object = Box<ShareBox>(ShareBox::Descriptor{
|
auto object = Box<ShareBox>(ShareBox::Descriptor{
|
||||||
.session = &peer->session(),
|
.session = &peer->session(),
|
||||||
.copyCallback = std::move(copyCallback),
|
.copyCallback = std::move(copyCallback),
|
||||||
.submitCallback = std::move(submitCallback),
|
.submitCallback = std::move(submitCallback), // #TODO forum forward
|
||||||
.filterCallback = [](auto peer) { return peer->canWrite(); },
|
.filterCallback = [](auto peer) { return peer->canWrite(); },
|
||||||
});
|
});
|
||||||
*box = Ui::MakeWeak(object.data());
|
*box = Ui::MakeWeak(object.data());
|
||||||
|
|
|
@ -1292,11 +1292,10 @@ void FastShareMessage(
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto error = [&] {
|
const auto error = [&] {
|
||||||
for (const auto peer : result) {
|
for (const auto peer : result) { // #TODO forum forward
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
peer,
|
peer,
|
||||||
items,
|
{ .forward = &items, .text = &comment });
|
||||||
comment);
|
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
return std::make_pair(error, peer);
|
return std::make_pair(error, peer);
|
||||||
}
|
}
|
||||||
|
@ -1399,7 +1398,7 @@ void FastShareMessage(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
auto filterCallback = [isGame](PeerData *peer) {
|
auto filterCallback = [isGame](PeerData *peer) {
|
||||||
if (peer->canWrite()) {
|
if (peer->canWrite()) { // #TODO forum forward
|
||||||
if (auto channel = peer->asChannel()) {
|
if (auto channel = peer->asChannel()) {
|
||||||
return isGame ? (!channel->isBroadcast()) : true;
|
return isGame ? (!channel->isBroadcast()) : true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1642,7 +1642,7 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
|
||||||
return rpl::single(false) | rpl::type_erased();
|
return rpl::single(false) | rpl::type_erased();
|
||||||
}
|
}
|
||||||
return rpl::combine(
|
return rpl::combine(
|
||||||
Data::CanWriteValue(peer.get()),
|
Data::CanWriteValue(peer, false),
|
||||||
_call->joinAsValue()
|
_call->joinAsValue()
|
||||||
) | rpl::map([=](bool can, not_null<PeerData*> joinAs) {
|
) | rpl::map([=](bool can, not_null<PeerData*> joinAs) {
|
||||||
return can && joinAs->isSelf();
|
return can && joinAs->isSelf();
|
||||||
|
|
|
@ -845,7 +845,7 @@ void Panel::setupMembers() {
|
||||||
_members->addMembersRequests(
|
_members->addMembersRequests(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
if (!_peer->isBroadcast()
|
if (!_peer->isBroadcast()
|
||||||
&& _peer->canWrite()
|
&& _peer->canWrite(false)
|
||||||
&& _call->joinAs()->isSelf()) {
|
&& _call->joinAs()->isSelf()) {
|
||||||
addMembers();
|
addMembers();
|
||||||
} else if (const auto channel = _peer->asChannel()) {
|
} else if (const auto channel = _peer->asChannel()) {
|
||||||
|
|
|
@ -141,11 +141,10 @@ object_ptr<ShareBox> ShareInviteLinkBox(
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto error = [&] {
|
const auto error = [&] {
|
||||||
for (const auto peer : result) {
|
for (const auto peer : result) { // #TODO forum forward
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
peer,
|
peer,
|
||||||
{},
|
{ .text = &comment });
|
||||||
comment);
|
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
return std::make_pair(error, peer);
|
return std::make_pair(error, peer);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +195,7 @@ object_ptr<ShareBox> ShareInviteLinkBox(
|
||||||
showToast(tr::lng_share_done(tr::now));
|
showToast(tr::lng_share_done(tr::now));
|
||||||
};
|
};
|
||||||
auto filterCallback = [](PeerData *peer) {
|
auto filterCallback = [](PeerData *peer) {
|
||||||
return peer->canWrite();
|
return peer->canWrite(); // #TODO forum forward
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto scheduleStyle = [&] {
|
const auto scheduleStyle = [&] {
|
||||||
|
|
|
@ -552,11 +552,14 @@ bool ChannelData::canPublish() const {
|
||||||
|| (adminRights() & AdminRight::PostMessages);
|
|| (adminRights() & AdminRight::PostMessages);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChannelData::canWrite() const {
|
bool ChannelData::canWrite(bool checkForForum) const {
|
||||||
// Duplicated in Data::CanWriteValue().
|
// Duplicated in Data::CanWriteValue().
|
||||||
const auto allowed = amIn()
|
const auto allowed = amIn()
|
||||||
|| ((flags() & Flag::HasLink) && !(flags() & Flag::JoinToWrite));
|
|| ((flags() & Flag::HasLink) && !(flags() & Flag::JoinToWrite));
|
||||||
return allowed && (canPublish()
|
const auto forumRestriction = checkForForum && isForum();
|
||||||
|
return allowed
|
||||||
|
&& !forumRestriction
|
||||||
|
&& (canPublish()
|
||||||
|| (!isBroadcast()
|
|| (!isBroadcast()
|
||||||
&& !amRestricted(Restriction::SendMessages)));
|
&& !amRestricted(Restriction::SendMessages)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,7 @@ public:
|
||||||
void setDefaultRestrictions(ChatRestrictions rights);
|
void setDefaultRestrictions(ChatRestrictions rights);
|
||||||
|
|
||||||
// Like in ChatData.
|
// Like in ChatData.
|
||||||
[[nodiscard]] bool canWrite() const;
|
[[nodiscard]] bool canWrite(bool checkForForum = true) const;
|
||||||
[[nodiscard]] bool allowsForwarding() const;
|
[[nodiscard]] bool allowsForwarding() const;
|
||||||
[[nodiscard]] bool canEditInformation() const;
|
[[nodiscard]] bool canEditInformation() const;
|
||||||
[[nodiscard]] bool canEditPermissions() const;
|
[[nodiscard]] bool canEditPermissions() const;
|
||||||
|
|
|
@ -160,6 +160,8 @@ void Forum::applyReceivedTopics(const MTPmessages_ForumTopics &result) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Forum::applyTopicDeleted(MsgId rootId) {
|
void Forum::applyTopicDeleted(MsgId rootId) {
|
||||||
|
_topicsDeleted.emplace(rootId);
|
||||||
|
|
||||||
const auto i = _topics.find(rootId);
|
const auto i = _topics.find(rootId);
|
||||||
if (i != end(_topics)) {
|
if (i != end(_topics)) {
|
||||||
const auto raw = i->second.get();
|
const auto raw = i->second.get();
|
||||||
|
@ -192,6 +194,7 @@ void Forum::applyReceivedTopics(
|
||||||
}
|
}
|
||||||
applyTopicDeleted(rootId);
|
applyTopicDeleted(rootId);
|
||||||
}, [&](const MTPDforumTopic &data) {
|
}, [&](const MTPDforumTopic &data) {
|
||||||
|
_topicsDeleted.remove(rootId);
|
||||||
const auto i = _topics.find(rootId);
|
const auto i = _topics.find(rootId);
|
||||||
const auto creating = (i == end(_topics));
|
const auto creating = (i == end(_topics));
|
||||||
const auto raw = creating
|
const auto raw = creating
|
||||||
|
@ -410,6 +413,10 @@ ForumTopic *Forum::enforceTopicFor(MsgId rootId) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Forum::topicDeleted(MsgId rootId) const {
|
||||||
|
return _topicsDeleted.contains(rootId);
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<> Forum::chatsListChanges() const {
|
rpl::producer<> Forum::chatsListChanges() const {
|
||||||
return _chatsListChanges.events();
|
return _chatsListChanges.events();
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ public:
|
||||||
void applyTopicDeleted(MsgId rootId);
|
void applyTopicDeleted(MsgId rootId);
|
||||||
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
||||||
[[nodiscard]] ForumTopic *enforceTopicFor(MsgId rootId);
|
[[nodiscard]] ForumTopic *enforceTopicFor(MsgId rootId);
|
||||||
|
[[nodiscard]] bool topicDeleted(MsgId rootId) const;
|
||||||
|
|
||||||
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
||||||
|
|
||||||
|
@ -90,6 +91,7 @@ private:
|
||||||
const not_null<History*> _history;
|
const not_null<History*> _history;
|
||||||
|
|
||||||
base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics;
|
base::flat_map<MsgId, std::unique_ptr<ForumTopic>> _topics;
|
||||||
|
base::flat_set<MsgId> _topicsDeleted;
|
||||||
rpl::event_stream<not_null<ForumTopic*>> _topicDestroyed;
|
rpl::event_stream<not_null<ForumTopic*>> _topicDestroyed;
|
||||||
Dialogs::MainList _topicsList;
|
Dialogs::MainList _topicsList;
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,13 @@ bool ForumTopic::my() const {
|
||||||
return (_flags & Flag::My);
|
return (_flags & Flag::My);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ForumTopic::canWrite() const {
|
||||||
|
const auto channel = this->channel();
|
||||||
|
return channel->amIn()
|
||||||
|
&& !channel->amRestricted(ChatRestriction::SendMessages)
|
||||||
|
&& (!closed() || canToggleClosed());
|
||||||
|
}
|
||||||
|
|
||||||
bool ForumTopic::canEdit() const {
|
bool ForumTopic::canEdit() const {
|
||||||
return my() || channel()->canManageTopics();
|
return my() || channel()->canManageTopics();
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
[[nodiscard]] MsgId rootId() const;
|
[[nodiscard]] MsgId rootId() const;
|
||||||
|
|
||||||
[[nodiscard]] bool my() const;
|
[[nodiscard]] bool my() const;
|
||||||
|
[[nodiscard]] bool canWrite() const;
|
||||||
[[nodiscard]] bool canEdit() const;
|
[[nodiscard]] bool canEdit() const;
|
||||||
[[nodiscard]] bool canToggleClosed() const;
|
[[nodiscard]] bool canToggleClosed() const;
|
||||||
[[nodiscard]] bool canTogglePinned() const;
|
[[nodiscard]] bool canTogglePinned() const;
|
||||||
|
|
|
@ -937,11 +937,11 @@ Data::ForumTopic *PeerData::forumTopicFor(MsgId rootId) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PeerData::canWrite() const {
|
bool PeerData::canWrite(bool checkForForum) const {
|
||||||
if (const auto user = asUser()) {
|
if (const auto user = asUser()) {
|
||||||
return user->canWrite();
|
return user->canWrite();
|
||||||
} else if (const auto channel = asChannel()) {
|
} else if (const auto channel = asChannel()) {
|
||||||
return channel->canWrite();
|
return channel->canWrite(checkForForum);
|
||||||
} else if (const auto chat = asChat()) {
|
} else if (const auto chat = asChat()) {
|
||||||
return chat->canWrite();
|
return chat->canWrite();
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ public:
|
||||||
return _notify;
|
return _notify;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool canWrite() const;
|
[[nodiscard]] bool canWrite(bool checkForForum = true) const;
|
||||||
[[nodiscard]] bool allowsForwarding() const;
|
[[nodiscard]] bool allowsForwarding() const;
|
||||||
[[nodiscard]] Data::RestrictionCheckResult amRestricted(
|
[[nodiscard]] Data::RestrictionCheckResult amRestricted(
|
||||||
ChatRestriction right) const;
|
ChatRestriction right) const;
|
||||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_chat.h"
|
#include "data/data_chat.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_message_reactions.h"
|
#include "data/data_message_reactions.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
@ -201,10 +202,11 @@ rpl::producer<bool> CanWriteValue(ChatData *chat) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> CanWriteValue(ChannelData *channel) {
|
rpl::producer<bool> CanWriteValue(ChannelData *channel, bool checkForForum) {
|
||||||
using Flag = ChannelDataFlag;
|
using Flag = ChannelDataFlag;
|
||||||
const auto mask = 0
|
const auto mask = 0
|
||||||
| Flag::Left
|
| Flag::Left
|
||||||
|
| Flag::Forum
|
||||||
| Flag::JoinToWrite
|
| Flag::JoinToWrite
|
||||||
| Flag::HasLink
|
| Flag::HasLink
|
||||||
| Flag::Forbidden
|
| Flag::Forbidden
|
||||||
|
@ -221,15 +223,19 @@ rpl::producer<bool> CanWriteValue(ChannelData *channel) {
|
||||||
DefaultRestrictionValue(
|
DefaultRestrictionValue(
|
||||||
channel,
|
channel,
|
||||||
ChatRestriction::SendMessages),
|
ChatRestriction::SendMessages),
|
||||||
[](
|
[=](
|
||||||
ChannelDataFlags flags,
|
ChannelDataFlags flags,
|
||||||
bool postMessagesRight,
|
bool postMessagesRight,
|
||||||
bool sendMessagesRestriction,
|
bool sendMessagesRestriction,
|
||||||
bool defaultSendMessagesRestriction) {
|
bool defaultSendMessagesRestriction) {
|
||||||
const auto notAmInFlags = Flag::Left | Flag::Forbidden;
|
const auto notAmInFlags = Flag::Left | Flag::Forbidden;
|
||||||
|
const auto forumRestriction = checkForForum
|
||||||
|
&& (flags & Flag::Forum);
|
||||||
const auto allowed = !(flags & notAmInFlags)
|
const auto allowed = !(flags & notAmInFlags)
|
||||||
|| ((flags & Flag::HasLink) && !(flags & Flag::JoinToWrite));
|
|| ((flags & Flag::HasLink) && !(flags & Flag::JoinToWrite));
|
||||||
return allowed && (postMessagesRight
|
return allowed
|
||||||
|
&& !forumRestriction
|
||||||
|
&& (postMessagesRight
|
||||||
|| (flags & Flag::Creator)
|
|| (flags & Flag::Creator)
|
||||||
|| (!(flags & Flag::Broadcast)
|
|| (!(flags & Flag::Broadcast)
|
||||||
&& !sendMessagesRestriction
|
&& !sendMessagesRestriction
|
||||||
|
@ -237,17 +243,52 @@ rpl::producer<bool> CanWriteValue(ChannelData *channel) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer) {
|
rpl::producer<bool> CanWriteValue(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
bool checkForForum) {
|
||||||
if (auto user = peer->asUser()) {
|
if (auto user = peer->asUser()) {
|
||||||
return CanWriteValue(user);
|
return CanWriteValue(user);
|
||||||
} else if (auto chat = peer->asChat()) {
|
} else if (auto chat = peer->asChat()) {
|
||||||
return CanWriteValue(chat);
|
return CanWriteValue(chat);
|
||||||
} else if (auto channel = peer->asChannel()) {
|
} else if (auto channel = peer->asChannel()) {
|
||||||
return CanWriteValue(channel);
|
return CanWriteValue(channel, checkForForum);
|
||||||
}
|
}
|
||||||
Unexpected("Bad peer value in CanWriteValue");
|
Unexpected("Bad peer value in CanWriteValue");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<bool> CanWriteValue(not_null<ForumTopic*> topic) {
|
||||||
|
using Flag = ChannelDataFlag;
|
||||||
|
const auto mask = 0
|
||||||
|
| Flag::Left
|
||||||
|
| Flag::JoinToWrite
|
||||||
|
| Flag::Forum
|
||||||
|
| Flag::Forbidden;
|
||||||
|
const auto channel = topic->channel();
|
||||||
|
return rpl::combine(
|
||||||
|
PeerFlagsValue(channel.get(), mask),
|
||||||
|
RestrictionValue(
|
||||||
|
channel,
|
||||||
|
ChatRestriction::SendMessages),
|
||||||
|
DefaultRestrictionValue(
|
||||||
|
channel,
|
||||||
|
ChatRestriction::SendMessages),
|
||||||
|
topic->session().changes().topicFlagsValue(
|
||||||
|
topic,
|
||||||
|
TopicUpdate::Flag::Closed),
|
||||||
|
[=](
|
||||||
|
ChannelDataFlags flags,
|
||||||
|
bool sendMessagesRestriction,
|
||||||
|
bool defaultSendMessagesRestriction,
|
||||||
|
auto) {
|
||||||
|
const auto notAmInFlags = Flag::Left | Flag::Forbidden;
|
||||||
|
const auto allowed = !(flags & notAmInFlags);
|
||||||
|
return allowed
|
||||||
|
&& !sendMessagesRestriction
|
||||||
|
&& !defaultSendMessagesRestriction
|
||||||
|
&& (!topic->closed() || topic->canToggleClosed());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// This is duplicated in PeerData::canPinMessages().
|
// This is duplicated in PeerData::canPinMessages().
|
||||||
rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) {
|
rpl::producer<bool> CanPinMessagesValue(not_null<PeerData*> peer) {
|
||||||
using namespace rpl::mappers;
|
using namespace rpl::mappers;
|
||||||
|
|
|
@ -21,6 +21,7 @@ class Session;
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
struct Reaction;
|
struct Reaction;
|
||||||
|
class ForumTopic;
|
||||||
|
|
||||||
template <typename ChangeType, typename Error, typename Generator>
|
template <typename ChangeType, typename Error, typename Generator>
|
||||||
inline auto FlagsValueWithMask(
|
inline auto FlagsValueWithMask(
|
||||||
|
@ -102,8 +103,13 @@ inline auto PeerFullFlagValue(
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(UserData *user);
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(UserData *user);
|
||||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChatData *chat);
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChatData *chat);
|
||||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChannelData *channel);
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(
|
||||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<PeerData*> peer);
|
ChannelData *channel,
|
||||||
|
bool checkForForum = true);
|
||||||
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
bool checkForForum = true);
|
||||||
|
[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<ForumTopic*> topic);
|
||||||
[[nodiscard]] rpl::producer<bool> CanPinMessagesValue(
|
[[nodiscard]] rpl::producer<bool> CanPinMessagesValue(
|
||||||
not_null<PeerData*> peer);
|
not_null<PeerData*> peer);
|
||||||
[[nodiscard]] rpl::producer<bool> CanManageGroupCallValue(
|
[[nodiscard]] rpl::producer<bool> CanManageGroupCallValue(
|
||||||
|
|
|
@ -1133,6 +1133,9 @@ void History::applyServiceChanges(
|
||||||
if (const auto icon = data.vicon_emoji_id()) {
|
if (const auto icon = data.vicon_emoji_id()) {
|
||||||
topic->applyIconId(icon->v);
|
topic->applyIconId(icon->v);
|
||||||
}
|
}
|
||||||
|
if (const auto closed = data.vclosed()) {
|
||||||
|
topic->setClosed(mtpIsTrue(*closed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [](const auto &) {
|
}, [](const auto &) {
|
||||||
});
|
});
|
||||||
|
|
|
@ -76,6 +76,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_message_reactions.h"
|
#include "data/data_message_reactions.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
#include "data/data_photo.h"
|
#include "data/data_photo.h"
|
||||||
#include "data/data_photo_media.h"
|
#include "data/data_photo_media.h"
|
||||||
|
@ -2003,7 +2004,6 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto selectedState = getSelectionState();
|
auto selectedState = getSelectionState();
|
||||||
auto canSendMessages = _peer->canWrite();
|
|
||||||
|
|
||||||
// -2 - has full selected items, but not over, -1 - has selection, but no over, 0 - no selection, 1 - over text, 2 - over full selected items
|
// -2 - has full selected items, but not over, -1 - has selection, but no over, 0 - no selection, 1 - over text, 2 - over full selected items
|
||||||
auto isUponSelected = 0;
|
auto isUponSelected = 0;
|
||||||
|
@ -2079,7 +2079,18 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto itemId = item->fullId();
|
const auto itemId = item->fullId();
|
||||||
if (canSendMessages) {
|
const auto canReply = [&] {
|
||||||
|
const auto peer = item->history()->peer;
|
||||||
|
if (const auto forum = item->history()->peer->forum()) {
|
||||||
|
const auto topicRootId = item->topicRootId();
|
||||||
|
const auto topic = item->topic();
|
||||||
|
return topic
|
||||||
|
? topic->canWrite()
|
||||||
|
: peer->canWrite(!topicRootId);
|
||||||
|
}
|
||||||
|
return peer->canWrite();
|
||||||
|
}();
|
||||||
|
if (canReply) {
|
||||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
||||||
_widget->replyToMessage(itemId);
|
_widget->replyToMessage(itemId);
|
||||||
}, &st::menuIconReply);
|
}, &st::menuIconReply);
|
||||||
|
|
|
@ -798,7 +798,13 @@ bool HistoryItem::canBeEdited() const {
|
||||||
if (isPost() && channel->canEditMessages()) {
|
if (isPost() && channel->canEditMessages()) {
|
||||||
return true;
|
return true;
|
||||||
} else if (out()) {
|
} else if (out()) {
|
||||||
return isPost() ? channel->canPublish() : channel->canWrite();
|
if (isPost()) {
|
||||||
|
return channel->canPublish();
|
||||||
|
} else if (const auto topic = this->topic()) {
|
||||||
|
return topic->canWrite();
|
||||||
|
} else {
|
||||||
|
return channel->canWrite();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,44 +107,52 @@ namespace {
|
||||||
|
|
||||||
QString GetErrorTextForSending(
|
QString GetErrorTextForSending(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const HistoryItemsList &items,
|
SendingErrorRequest request) {
|
||||||
const TextWithTags &comment,
|
const auto forum = request.topicRootId ? peer->forum() : nullptr;
|
||||||
bool ignoreSlowmodeCountdown) {
|
const auto topic = forum
|
||||||
if (!peer->canWrite()) {
|
? forum->topicFor(request.topicRootId)
|
||||||
|
: nullptr;
|
||||||
|
if (!(topic ? topic->canWrite() : peer->canWrite())) {
|
||||||
return tr::lng_forward_cant(tr::now);
|
return tr::lng_forward_cant(tr::now);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &item : items) {
|
if (request.forward) {
|
||||||
if (const auto media = item->media()) {
|
for (const auto &item : *request.forward) {
|
||||||
const auto error = media->errorTextForForward(peer);
|
if (const auto media = item->media()) {
|
||||||
if (!error.isEmpty() && error != qstr("skip")) {
|
const auto error = media->errorTextForForward(peer);
|
||||||
return error;
|
if (!error.isEmpty() && error != qstr("skip")) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto error = Data::RestrictionError(
|
const auto error = Data::RestrictionError(
|
||||||
peer,
|
peer,
|
||||||
ChatRestriction::SendInline);
|
ChatRestriction::SendInline);
|
||||||
if (error && HasInlineItems(items)) {
|
if (error && request.forward && HasInlineItems(*request.forward)) {
|
||||||
return *error;
|
return *error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (peer->slowmodeApplied()) {
|
if (peer->slowmodeApplied()) {
|
||||||
|
const auto hasText = (request.text && !request.text->empty());
|
||||||
|
const auto count = (hasText ? 1 : 0)
|
||||||
|
+ (request.forward ? int(request.forward->size()) : 0);
|
||||||
if (const auto history = peer->owner().historyLoaded(peer)) {
|
if (const auto history = peer->owner().historyLoaded(peer)) {
|
||||||
if (!ignoreSlowmodeCountdown
|
if (!request.ignoreSlowmodeCountdown
|
||||||
&& (history->latestSendingMessage() != nullptr)
|
&& (history->latestSendingMessage() != nullptr)
|
||||||
&& (!items.empty() || !comment.text.isEmpty())) {
|
&& (count > 0)) {
|
||||||
return tr::lng_slowmode_no_many(tr::now);
|
return tr::lng_slowmode_no_many(tr::now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (comment.text.size() > MaxMessageSize) {
|
if (request.text && request.text->text.size() > MaxMessageSize) {
|
||||||
return tr::lng_slowmode_too_long(tr::now);
|
return tr::lng_slowmode_too_long(tr::now);
|
||||||
} else if (!items.empty() && !comment.text.isEmpty()) {
|
} else if (hasText && count > 1) {
|
||||||
return tr::lng_slowmode_no_many(tr::now);
|
return tr::lng_slowmode_no_many(tr::now);
|
||||||
} else if (items.size() > 1) {
|
} else if (count > 1) {
|
||||||
const auto albumForward = [&] {
|
const auto albumForward = [&] {
|
||||||
if (const auto groupId = items.front()->groupId()) {
|
const auto first = request.forward->front();
|
||||||
for (const auto &item : items) {
|
if (const auto groupId = first->groupId()) {
|
||||||
|
for (const auto &item : *request.forward) {
|
||||||
if (item->groupId() != groupId) {
|
if (item->groupId() != groupId) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +167,7 @@ QString GetErrorTextForSending(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (const auto left = peer->slowmodeSecondsLeft()) {
|
if (const auto left = peer->slowmodeSecondsLeft()) {
|
||||||
if (!ignoreSlowmodeCountdown) {
|
if (!request.ignoreSlowmodeCountdown) {
|
||||||
return tr::lng_slowmode_enabled(
|
return tr::lng_slowmode_enabled(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_left,
|
lt_left,
|
||||||
|
@ -242,13 +250,6 @@ MTPMessageReplyHeader NewMessageReplyHeader(const Api::SendAction &action) {
|
||||||
return MTPMessageReplyHeader();
|
return MTPMessageReplyHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString GetErrorTextForSending(
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
const HistoryItemsList &items,
|
|
||||||
bool ignoreSlowmodeCountdown) {
|
|
||||||
return GetErrorTextForSending(peer, items, {}, ignoreSlowmodeCountdown);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextWithEntities DropCustomEmoji(TextWithEntities text) {
|
TextWithEntities DropCustomEmoji(TextWithEntities text) {
|
||||||
text.entities.erase(
|
text.entities.erase(
|
||||||
ranges::remove(
|
ranges::remove(
|
||||||
|
|
|
@ -40,15 +40,17 @@ void RequestDependentMessageData(
|
||||||
MsgId replyToId);
|
MsgId replyToId);
|
||||||
[[nodiscard]] MTPMessageReplyHeader NewMessageReplyHeader(
|
[[nodiscard]] MTPMessageReplyHeader NewMessageReplyHeader(
|
||||||
const Api::SendAction &action);
|
const Api::SendAction &action);
|
||||||
|
|
||||||
|
struct SendingErrorRequest {
|
||||||
|
MsgId topicRootId = 0;
|
||||||
|
const HistoryItemsList *forward = nullptr;
|
||||||
|
const TextWithTags *text = nullptr;
|
||||||
|
bool ignoreSlowmodeCountdown = false;
|
||||||
|
};
|
||||||
[[nodiscard]] QString GetErrorTextForSending(
|
[[nodiscard]] QString GetErrorTextForSending(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
const HistoryItemsList &items,
|
SendingErrorRequest request);
|
||||||
bool ignoreSlowmodeCountdown = false);
|
|
||||||
[[nodiscard]] QString GetErrorTextForSending(
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
const HistoryItemsList &items,
|
|
||||||
const TextWithTags &comment,
|
|
||||||
bool ignoreSlowmodeCountdown = false);
|
|
||||||
[[nodiscard]] TextWithEntities DropCustomEmoji(TextWithEntities text);
|
[[nodiscard]] TextWithEntities DropCustomEmoji(TextWithEntities text);
|
||||||
|
|
||||||
class HistoryMessage final : public HistoryItem {
|
class HistoryMessage final : public HistoryItem {
|
||||||
|
|
|
@ -65,6 +65,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#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_chat.h"
|
#include "data/data_chat.h"
|
||||||
|
#include "data/data_forum.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_chat_filters.h"
|
#include "data/data_chat_filters.h"
|
||||||
#include "data/data_scheduled_messages.h"
|
#include "data/data_scheduled_messages.h"
|
||||||
|
@ -1902,8 +1904,8 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||||
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
|
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
|
||||||
clearFieldText(0, fieldHistoryAction);
|
clearFieldText(0, fieldHistoryAction);
|
||||||
_field->setFocus();
|
_field->setFocus();
|
||||||
_replyEditMsg = nullptr;
|
_processingReplyItem = _replyEditMsg = nullptr;
|
||||||
_replyToId = 0;
|
_processingReplyId = _replyToId = 0;
|
||||||
setEditMsgId(0);
|
setEditMsgId(0);
|
||||||
if (fieldWillBeHiddenAfterEdit) {
|
if (fieldWillBeHiddenAfterEdit) {
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
|
@ -1926,23 +1928,25 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
|
||||||
_parsedLinks = _fieldLinksParser->list().current();
|
_parsedLinks = _fieldLinksParser->list().current();
|
||||||
_previewState = draft->previewState;
|
_previewState = draft->previewState;
|
||||||
|
|
||||||
_replyEditMsg = nullptr;
|
_processingReplyItem = _replyEditMsg = nullptr;
|
||||||
|
_processingReplyId = _replyToId = 0;
|
||||||
if (const auto editDraft = _history->localEditDraft({})) {
|
if (const auto editDraft = _history->localEditDraft({})) {
|
||||||
setEditMsgId(editDraft->msgId);
|
setEditMsgId(editDraft->msgId);
|
||||||
_replyToId = 0;
|
|
||||||
} else {
|
} else {
|
||||||
_replyToId = readyToForward() ? 0 : _history->localDraft({})->msgId;
|
|
||||||
setEditMsgId(0);
|
setEditMsgId(0);
|
||||||
}
|
}
|
||||||
updateCmdStartShown();
|
updateCmdStartShown();
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
refreshTopBarActiveChat();
|
refreshTopBarActiveChat();
|
||||||
if (_editMsgId || _replyToId) {
|
if (_editMsgId) {
|
||||||
updateReplyEditTexts();
|
updateReplyEditTexts();
|
||||||
if (!_replyEditMsg) {
|
if (!_replyEditMsg) {
|
||||||
requestMessageData(_editMsgId ? _editMsgId : _replyToId);
|
requestMessageData(_editMsgId);
|
||||||
}
|
}
|
||||||
|
} else if (!readyToForward()) {
|
||||||
|
_processingReplyId = _history->localDraft({})->msgId;
|
||||||
|
processReply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2105,8 +2109,8 @@ void HistoryWidget::showHistory(
|
||||||
HistoryView::Element::ClearGlobal();
|
HistoryView::Element::ClearGlobal();
|
||||||
|
|
||||||
_saveEditMsgRequestId = 0;
|
_saveEditMsgRequestId = 0;
|
||||||
_replyEditMsg = nullptr;
|
_processingReplyItem = _replyEditMsg = nullptr;
|
||||||
_editMsgId = _replyToId = 0;
|
_processingReplyId = _editMsgId = _replyToId = 0;
|
||||||
_previewData = nullptr;
|
_previewData = nullptr;
|
||||||
_previewCache.clear();
|
_previewCache.clear();
|
||||||
_fieldBarCancel->hide();
|
_fieldBarCancel->hide();
|
||||||
|
@ -2503,7 +2507,7 @@ void HistoryWidget::setupScheduledToggle() {
|
||||||
|
|
||||||
void HistoryWidget::refreshScheduledToggle() {
|
void HistoryWidget::refreshScheduledToggle() {
|
||||||
const auto has = _history
|
const auto has = _history
|
||||||
&& _peer->canWrite()
|
&& _canSendMessages
|
||||||
&& (session().data().scheduledMessages().count(_history) > 0);
|
&& (session().data().scheduledMessages().count(_history) > 0);
|
||||||
if (!_scheduled && has) {
|
if (!_scheduled && has) {
|
||||||
_scheduled.create(this, st::historyScheduledToggle);
|
_scheduled.create(this, st::historyScheduledToggle);
|
||||||
|
@ -2564,9 +2568,15 @@ bool HistoryWidget::canWriteMessage() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<QString> HistoryWidget::writeRestriction() const {
|
std::optional<QString> HistoryWidget::writeRestriction() const {
|
||||||
return _peer
|
auto result = _peer
|
||||||
? Data::RestrictionError(_peer, ChatRestriction::SendMessages)
|
? Data::RestrictionError(_peer, ChatRestriction::SendMessages)
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
} else if (_peer && _peer->isForum()) {
|
||||||
|
return u"You can reply to messages in topics."_q;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::updateControlsVisibility() {
|
void HistoryWidget::updateControlsVisibility() {
|
||||||
|
@ -3699,11 +3709,17 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||||
message.webPageId = webPageId;
|
message.webPageId = webPageId;
|
||||||
|
|
||||||
if (_canSendMessages) {
|
if (_canSendMessages) {
|
||||||
|
const auto topicRootId = _replyEditMsg
|
||||||
|
? _replyEditMsg->topicRootId()
|
||||||
|
: 0;
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
_peer,
|
_peer,
|
||||||
_toForward.items,
|
{
|
||||||
message.textWithTags,
|
.topicRootId = topicRootId,
|
||||||
options.scheduled);
|
.forward = &_toForward.items,
|
||||||
|
.text = &message.textWithTags,
|
||||||
|
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||||
|
});
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
Ui::ShowMultilineToast({
|
Ui::ShowMultilineToast({
|
||||||
.parentOverride = Window::Show(controller()).toastParent(),
|
.parentOverride = Window::Show(controller()).toastParent(),
|
||||||
|
@ -4027,7 +4043,7 @@ void HistoryWidget::chooseAttach(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_peer || !_peer->canWrite()) {
|
if (!_peer || !_canSendMessages) {
|
||||||
return;
|
return;
|
||||||
} else if (const auto error = Data::RestrictionError(
|
} else if (const auto error = Data::RestrictionError(
|
||||||
_peer,
|
_peer,
|
||||||
|
@ -5248,6 +5264,10 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
||||||
if (item == _replyEditMsg && _replyToId) {
|
if (item == _replyEditMsg && _replyToId) {
|
||||||
cancelReply();
|
cancelReply();
|
||||||
}
|
}
|
||||||
|
if (item == _processingReplyItem) {
|
||||||
|
_processingReplyId = 0;
|
||||||
|
_processingReplyItem = nullptr;
|
||||||
|
}
|
||||||
if (_kbReplyTo && item == _kbReplyTo) {
|
if (_kbReplyTo && item == _kbReplyTo) {
|
||||||
toggleKeyboard();
|
toggleKeyboard();
|
||||||
_kbReplyTo = nullptr;
|
_kbReplyTo = nullptr;
|
||||||
|
@ -6080,7 +6100,7 @@ void HistoryWidget::fieldTabbed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
|
void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
|
||||||
if (!_peer || !_peer->canWrite()) {
|
if (!_peer || !_canSendMessages) {
|
||||||
return;
|
return;
|
||||||
} else if (showSlowmodeError()) {
|
} else if (showSlowmodeError()) {
|
||||||
return;
|
return;
|
||||||
|
@ -6547,7 +6567,7 @@ bool HistoryWidget::sendExistingDocument(
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
return false;
|
return false;
|
||||||
} else if (!_peer
|
} else if (!_peer
|
||||||
|| !_peer->canWrite()
|
|| !_canSendMessages
|
||||||
|| showSlowmodeError()
|
|| showSlowmodeError()
|
||||||
|| ShowSendPremiumError(controller(), document)) {
|
|| ShowSendPremiumError(controller(), document)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -6583,7 +6603,7 @@ bool HistoryWidget::sendExistingPhoto(
|
||||||
Ui::MakeInformBox(*error),
|
Ui::MakeInformBox(*error),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
return false;
|
return false;
|
||||||
} else if (!_peer || !_peer->canWrite()) {
|
} else if (!_peer || !_canSendMessages) {
|
||||||
return false;
|
return false;
|
||||||
} else if (showSlowmodeError()) {
|
} else if (showSlowmodeError()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -6657,24 +6677,80 @@ void HistoryWidget::replyToMessage(FullMsgId itemId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||||
if (!item->isRegular() || !_canSendMessages) {
|
_processingReplyId = item->id;
|
||||||
|
_processingReplyItem = item;
|
||||||
|
processReply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::processReply() {
|
||||||
|
const auto processContinue = [=] {
|
||||||
|
return crl::guard(_list, [=] {
|
||||||
|
if (!_peer || !_processingReplyId) {
|
||||||
|
return;
|
||||||
|
} else if (!_processingReplyItem) {
|
||||||
|
_processingReplyItem = _peer->owner().message(
|
||||||
|
_peer,
|
||||||
|
_processingReplyId);
|
||||||
|
if (!_processingReplyItem) {
|
||||||
|
_processingReplyId = 0;
|
||||||
|
} else {
|
||||||
|
processReply();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const auto processCancel = [=] {
|
||||||
|
_processingReplyId = 0;
|
||||||
|
_processingReplyItem = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_peer || !_processingReplyId) {
|
||||||
|
return processCancel();
|
||||||
|
} else if (!_processingReplyItem) {
|
||||||
|
session().api().requestMessageData(
|
||||||
|
_peer,
|
||||||
|
_processingReplyId,
|
||||||
|
processContinue());
|
||||||
return;
|
return;
|
||||||
} else if (item->history() == _migrated) {
|
} else if (_processingReplyItem->history() == _migrated) {
|
||||||
if (item->isService()) {
|
if (_processingReplyItem->isService()) {
|
||||||
controller()->show(Ui::MakeInformBox(tr::lng_reply_cant()));
|
controller()->show(Ui::MakeInformBox(tr::lng_reply_cant()));
|
||||||
} else {
|
} else {
|
||||||
const auto itemId = item->fullId();
|
const auto itemId = _processingReplyItem->fullId();
|
||||||
controller()->show(
|
controller()->show(
|
||||||
Ui::MakeConfirmBox({
|
Ui::MakeConfirmBox({
|
||||||
.text = tr::lng_reply_cant_forward(),
|
.text = tr::lng_reply_cant_forward(),
|
||||||
.confirmed = crl::guard(this, [=] {
|
.confirmed = crl::guard(this, [=] {
|
||||||
controller()->content()->setForwardDraft(
|
controller()->content()->setForwardDraft(
|
||||||
_peer->id,
|
_peer->id,
|
||||||
{ .ids = { 1, itemId } });
|
{.ids = { 1, itemId } });
|
||||||
}),
|
}),
|
||||||
.confirmText = tr::lng_selected_forward(),
|
.confirmText = tr::lng_selected_forward(),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
return processCancel();
|
||||||
|
} else if (_processingReplyItem->history() != _history
|
||||||
|
|| !_processingReplyItem->isRegular()) {
|
||||||
|
return processCancel();
|
||||||
|
} else if (const auto forum = _peer->forum()) {
|
||||||
|
const auto topicRootId = _processingReplyItem->topicRootId();
|
||||||
|
if (!topicRootId || forum->topicDeleted(topicRootId)) {
|
||||||
|
return processCancel();
|
||||||
|
} else if (const auto topic = forum->topicFor(topicRootId)) {
|
||||||
|
if (!topic->canWrite()) {
|
||||||
|
return processCancel();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
forum->requestTopic(topicRootId, processContinue());
|
||||||
|
}
|
||||||
|
} else if (!_peer->canWrite()) {
|
||||||
|
return processCancel();
|
||||||
|
}
|
||||||
|
setReplyFieldsFromProcessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryWidget::setReplyFieldsFromProcessing() {
|
||||||
|
if (!_processingReplyId || !_processingReplyItem) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6683,23 +6759,27 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||||
_composeSearch->hideAnimated();
|
_composeSearch->hideAnimated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto id = base::take(_processingReplyId);
|
||||||
|
const auto item = base::take(_processingReplyItem);
|
||||||
if (_editMsgId) {
|
if (_editMsgId) {
|
||||||
if (const auto localDraft = _history->localDraft({})) {
|
if (const auto localDraft = _history->localDraft({})) {
|
||||||
localDraft->msgId = item->id;
|
localDraft->msgId = id;
|
||||||
} else {
|
} else {
|
||||||
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
_history->setLocalDraft(std::make_unique<Data::Draft>(
|
||||||
TextWithTags(),
|
TextWithTags(),
|
||||||
item->id,
|
id,
|
||||||
MsgId(), // topicRootId
|
MsgId(),
|
||||||
MessageCursor(),
|
MessageCursor(),
|
||||||
Data::PreviewState::Allowed));
|
Data::PreviewState::Allowed));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_replyEditMsg = item;
|
_replyEditMsg = item;
|
||||||
_replyToId = item->id;
|
_replyToId = id;
|
||||||
updateReplyEditText(_replyEditMsg);
|
updateReplyEditText(_replyEditMsg);
|
||||||
|
updateCanSendMessage();
|
||||||
updateBotKeyboard();
|
updateBotKeyboard();
|
||||||
updateReplyToName();
|
updateReplyToName();
|
||||||
|
updateControlsVisibility();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
updateField();
|
updateField();
|
||||||
refreshTopBarActiveChat();
|
refreshTopBarActiveChat();
|
||||||
|
@ -6709,7 +6789,9 @@ void HistoryWidget::replyToMessage(not_null<HistoryItem*> item) {
|
||||||
_saveDraftStart = crl::now();
|
_saveDraftStart = crl::now();
|
||||||
saveDraft();
|
saveDraft();
|
||||||
|
|
||||||
_field->setFocus();
|
if (!_field->isHidden()) {
|
||||||
|
_field->setFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::editMessage(FullMsgId itemId) {
|
void HistoryWidget::editMessage(FullMsgId itemId) {
|
||||||
|
@ -6836,16 +6918,17 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) {
|
||||||
if (_replyToId) {
|
if (_replyToId) {
|
||||||
wasReply = true;
|
wasReply = true;
|
||||||
|
|
||||||
_replyEditMsg = nullptr;
|
_processingReplyItem = _replyEditMsg = nullptr;
|
||||||
_replyToId = 0;
|
_processingReplyId = _replyToId = 0;
|
||||||
mouseMoveEvent(0);
|
mouseMoveEvent(0);
|
||||||
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) {
|
if (!readyToForward() && (!_previewData || _previewData->pendingTill < 0) && !_kbReplyTo) {
|
||||||
_fieldBarCancel->hide();
|
_fieldBarCancel->hide();
|
||||||
updateMouseTracking();
|
updateMouseTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBotKeyboard();
|
updateBotKeyboard();
|
||||||
refreshTopBarActiveChat();
|
refreshTopBarActiveChat();
|
||||||
|
updateCanSendMessage();
|
||||||
|
updateControlsVisibility();
|
||||||
updateControlsGeometry();
|
updateControlsGeometry();
|
||||||
update();
|
update();
|
||||||
} else if (const auto localDraft = (_history ? _history->localDraft({}) : nullptr)) {
|
} else if (const auto localDraft = (_history ? _history->localDraft({}) : nullptr)) {
|
||||||
|
@ -7085,14 +7168,7 @@ void HistoryWidget::updatePreview() {
|
||||||
void HistoryWidget::fullInfoUpdated() {
|
void HistoryWidget::fullInfoUpdated() {
|
||||||
auto refresh = false;
|
auto refresh = false;
|
||||||
if (_list) {
|
if (_list) {
|
||||||
auto newCanSendMessages = _peer->canWrite();
|
if (updateCanSendMessage()) {
|
||||||
if (newCanSendMessages != _canSendMessages) {
|
|
||||||
_canSendMessages = newCanSendMessages;
|
|
||||||
if (!_canSendMessages) {
|
|
||||||
cancelReply();
|
|
||||||
}
|
|
||||||
refreshScheduledToggle();
|
|
||||||
refreshSilentToggle();
|
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
checkFieldAutocomplete();
|
checkFieldAutocomplete();
|
||||||
|
@ -7134,14 +7210,7 @@ void HistoryWidget::handlePeerUpdate() {
|
||||||
|| (!isBlocked() && _joinChannel->isHidden() == isJoinChannel())) {
|
|| (!isBlocked() && _joinChannel->isHidden() == isJoinChannel())) {
|
||||||
resize = true;
|
resize = true;
|
||||||
}
|
}
|
||||||
bool newCanSendMessages = _peer->canWrite();
|
if (updateCanSendMessage()) {
|
||||||
if (newCanSendMessages != _canSendMessages) {
|
|
||||||
_canSendMessages = newCanSendMessages;
|
|
||||||
if (!_canSendMessages) {
|
|
||||||
cancelReply();
|
|
||||||
}
|
|
||||||
refreshScheduledToggle();
|
|
||||||
refreshSilentToggle();
|
|
||||||
resize = true;
|
resize = true;
|
||||||
}
|
}
|
||||||
updateControlsVisibility();
|
updateControlsVisibility();
|
||||||
|
@ -7151,6 +7220,24 @@ void HistoryWidget::handlePeerUpdate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryWidget::updateCanSendMessage() {
|
||||||
|
const auto replyTo = (_replyToId && !_editMsgId) ? _replyEditMsg : 0;
|
||||||
|
const auto topic = replyTo ? replyTo->topic() : nullptr;
|
||||||
|
const auto newCanSendMessages = topic
|
||||||
|
? topic->canWrite()
|
||||||
|
: _peer->canWrite();
|
||||||
|
if (_canSendMessages == newCanSendMessages) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_canSendMessages = newCanSendMessages;
|
||||||
|
if (!_canSendMessages) {
|
||||||
|
cancelReply();
|
||||||
|
}
|
||||||
|
refreshScheduledToggle();
|
||||||
|
refreshSilentToggle();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryWidget::forwardSelected() {
|
void HistoryWidget::forwardSelected() {
|
||||||
if (!_list) {
|
if (!_list) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -332,6 +332,8 @@ private:
|
||||||
bool cornerButtonsHas(HistoryView::CornerButtonType type) override;
|
bool cornerButtonsHas(HistoryView::CornerButtonType type) override;
|
||||||
|
|
||||||
void checkSuggestToGigagroup();
|
void checkSuggestToGigagroup();
|
||||||
|
void processReply();
|
||||||
|
void setReplyFieldsFromProcessing();
|
||||||
|
|
||||||
void initTabbedSelector();
|
void initTabbedSelector();
|
||||||
void initVoiceRecordBar();
|
void initVoiceRecordBar();
|
||||||
|
@ -382,6 +384,7 @@ private:
|
||||||
void toggleTabbedSelectorMode();
|
void toggleTabbedSelectorMode();
|
||||||
void recountChatWidth();
|
void recountChatWidth();
|
||||||
void handlePeerUpdate();
|
void handlePeerUpdate();
|
||||||
|
bool updateCanSendMessage();
|
||||||
void setMembersShowAreaActive(bool active);
|
void setMembersShowAreaActive(bool active);
|
||||||
void handleHistoryChange(not_null<const History*> history);
|
void handleHistoryChange(not_null<const History*> history);
|
||||||
void showAboutTopPromotion();
|
void showAboutTopPromotion();
|
||||||
|
@ -616,6 +619,9 @@ private:
|
||||||
Ui::Text::String _replyToName;
|
Ui::Text::String _replyToName;
|
||||||
int _replyToNameVersion = 0;
|
int _replyToNameVersion = 0;
|
||||||
|
|
||||||
|
MsgId _processingReplyId = 0;
|
||||||
|
HistoryItem *_processingReplyItem = nullptr;
|
||||||
|
|
||||||
Data::ResolvedForwardDraft _toForward;
|
Data::ResolvedForwardDraft _toForward;
|
||||||
Ui::Text::String _toForwardFrom, _toForwardText;
|
Ui::Text::String _toForwardFrom, _toForwardText;
|
||||||
int _toForwardNameVersion = 0;
|
int _toForwardNameVersion = 0;
|
||||||
|
|
|
@ -45,6 +45,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_photo_media.h"
|
#include "data/data_photo_media.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_groups.h"
|
#include "data/data_groups.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
@ -584,9 +585,11 @@ bool AddReplyToMessageAction(
|
||||||
not_null<ListWidget*> list) {
|
not_null<ListWidget*> list) {
|
||||||
const auto context = list->elementContext();
|
const auto context = list->elementContext();
|
||||||
const auto item = request.item;
|
const auto item = request.item;
|
||||||
|
const auto topic = item ? item->topic() : nullptr;
|
||||||
|
const auto peer = item ? item->history()->peer.get() : nullptr;
|
||||||
if (!item
|
if (!item
|
||||||
|| !item->isRegular()
|
|| !item->isRegular()
|
||||||
|| !item->history()->peer->canWrite()
|
|| (topic ? topic->canWrite() : !peer->canWrite())
|
||||||
|| (context != Context::History && context != Context::Replies)) {
|
|| (context != Context::History && context != Context::Replies)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2703,7 +2703,7 @@ bool Message::hasFastReply() const {
|
||||||
bool Message::displayFastReply() const {
|
bool Message::displayFastReply() const {
|
||||||
return hasFastReply()
|
return hasFastReply()
|
||||||
&& data()->isRegular()
|
&& data()->isRegular()
|
||||||
&& data()->history()->peer->canWrite()
|
&& data()->history()->peer->canWrite(false)
|
||||||
&& !delegate()->elementInSelectionMode();
|
&& !delegate()->elementInSelectionMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -609,9 +609,11 @@ void RepliesWidget::setupComposeControls() {
|
||||||
ChatRestriction::SendMessages);
|
ChatRestriction::SendMessages);
|
||||||
return restriction
|
return restriction
|
||||||
? restriction
|
? restriction
|
||||||
: _history->peer->canWrite()
|
: topicRestriction
|
||||||
? std::move(topicRestriction)
|
? std::move(topicRestriction)
|
||||||
: tr::lng_group_not_accessible(tr::now);
|
: !(_topic ? _topic->canWrite() : _history->peer->canWrite())
|
||||||
|
? tr::lng_group_not_accessible(tr::now)
|
||||||
|
: std::optional<QString>();
|
||||||
});
|
});
|
||||||
|
|
||||||
_composeControls->setHistory({
|
_composeControls->setHistory({
|
||||||
|
@ -1217,7 +1219,10 @@ void RepliesWidget::refreshJoinGroupButton() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const auto channel = _history->peer->asChannel();
|
const auto channel = _history->peer->asChannel();
|
||||||
if (channel->amIn() || channel->canWrite()) {
|
const auto canWrite = !channel->isForum()
|
||||||
|
? channel->canWrite()
|
||||||
|
: (_topic && _topic->canWrite());
|
||||||
|
if (channel->amIn() || canWrite) {
|
||||||
set(nullptr);
|
set(nullptr);
|
||||||
} else {
|
} else {
|
||||||
if (!_joinGroup) {
|
if (!_joinGroup) {
|
||||||
|
|
|
@ -129,7 +129,7 @@ void ShowChooseBox(
|
||||||
callback(peer);
|
callback(peer);
|
||||||
};
|
};
|
||||||
auto filter = [=](not_null<PeerData*> peer) -> bool {
|
auto filter = [=](not_null<PeerData*> peer) -> bool {
|
||||||
if (!peer->canWrite()) {
|
if (!peer->canWrite()) { // #TODO forum forward
|
||||||
return false;
|
return false;
|
||||||
} else if (const auto user = peer->asUser()) {
|
} else if (const auto user = peer->asUser()) {
|
||||||
if (user->isBot()) {
|
if (user->isBot()) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ SendAsPeers::SendAsPeers(not_null<Session*> session)
|
||||||
|
|
||||||
bool SendAsPeers::shouldChoose(not_null<PeerData*> peer) {
|
bool SendAsPeers::shouldChoose(not_null<PeerData*> peer) {
|
||||||
refresh(peer);
|
refresh(peer);
|
||||||
return peer->canWrite() && (list(peer).size() > 1);
|
return peer->canWrite(false) && (list(peer).size() > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendAsPeers::refresh(not_null<PeerData*> peer, bool force) {
|
void SendAsPeers::refresh(not_null<PeerData*> peer, bool force) {
|
||||||
|
|
|
@ -335,7 +335,10 @@ MainWidget::MainWidget(
|
||||||
_controller->activeChatValue(
|
_controller->activeChatValue(
|
||||||
) | rpl::map([](Dialogs::Key key) {
|
) | rpl::map([](Dialogs::Key key) {
|
||||||
const auto peer = key.peer();
|
const auto peer = key.peer();
|
||||||
auto canWrite = peer
|
const auto topic = key.topic();
|
||||||
|
auto canWrite = topic
|
||||||
|
? Data::CanWriteValue(topic)
|
||||||
|
: peer
|
||||||
? Data::CanWriteValue(peer)
|
? Data::CanWriteValue(peer)
|
||||||
: rpl::single(false);
|
: rpl::single(false);
|
||||||
return std::move(
|
return std::move(
|
||||||
|
@ -516,10 +519,10 @@ bool MainWidget::setForwardDraft(PeerId peerId, Data::ForwardDraft &&draft) {
|
||||||
Expects(peerId != 0);
|
Expects(peerId != 0);
|
||||||
|
|
||||||
const auto peer = session().data().peer(peerId);
|
const auto peer = session().data().peer(peerId);
|
||||||
|
const auto items = session().data().idsToItems(draft.ids);
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
peer,
|
peer, // #TODO forum forward
|
||||||
session().data().idsToItems(draft.ids),
|
{ .forward = &items, .ignoreSlowmodeCountdown = true });
|
||||||
true);
|
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
Ui::show(Ui::MakeInformBox(error), Ui::LayerOption::KeepOther);
|
Ui::show(Ui::MakeInformBox(error), Ui::LayerOption::KeepOther);
|
||||||
return false;
|
return false;
|
||||||
|
@ -541,7 +544,7 @@ bool MainWidget::shareUrl(
|
||||||
Expects(peerId != 0);
|
Expects(peerId != 0);
|
||||||
|
|
||||||
const auto peer = session().data().peer(peerId);
|
const auto peer = session().data().peer(peerId);
|
||||||
if (!peer->canWrite()) {
|
if (!peer->canWrite()) { // #TODO forum forward
|
||||||
_controller->show(Ui::MakeInformBox(tr::lng_share_cant()));
|
_controller->show(Ui::MakeInformBox(tr::lng_share_cant()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -575,7 +578,7 @@ bool MainWidget::inlineSwitchChosen(
|
||||||
Expects(peerId != 0);
|
Expects(peerId != 0);
|
||||||
|
|
||||||
const auto peer = session().data().peer(peerId);
|
const auto peer = session().data().peer(peerId);
|
||||||
if (!peer->canWrite()) {
|
if (!peer->canWrite()) { // #TODO forum forward
|
||||||
Ui::show(Ui::MakeInformBox(tr::lng_inline_switch_cant()));
|
Ui::show(Ui::MakeInformBox(tr::lng_inline_switch_cant()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -607,7 +610,7 @@ bool MainWidget::sendPaths(PeerId peerId) {
|
||||||
Expects(peerId != 0);
|
Expects(peerId != 0);
|
||||||
|
|
||||||
auto peer = session().data().peer(peerId);
|
auto peer = session().data().peer(peerId);
|
||||||
if (!peer->canWrite()) {
|
if (!peer->canWrite()) { // #TODO forum forward
|
||||||
Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant()));
|
Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant()));
|
||||||
return false;
|
return false;
|
||||||
} else if (const auto error = Data::RestrictionError(
|
} else if (const auto error = Data::RestrictionError(
|
||||||
|
@ -638,7 +641,7 @@ void MainWidget::onFilesOrForwardDrop(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto peer = session().data().peer(peerId);
|
auto peer = session().data().peer(peerId);
|
||||||
if (!peer->canWrite()) {
|
if (!peer->canWrite()) { // #TODO forum forward
|
||||||
Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant()));
|
Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_document_media.h"
|
#include "data/data_document_media.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_forum_topic.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -168,7 +169,9 @@ auto ActiveChat(not_null<Window::Controller*> controller) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CanWriteToActiveChat(not_null<Window::Controller*> controller) {
|
bool CanWriteToActiveChat(not_null<Window::Controller*> controller) {
|
||||||
if (const auto history = ActiveChat(controller).history()) {
|
if (const auto topic = ActiveChat(controller).topic()) {
|
||||||
|
return topic->canWrite();
|
||||||
|
} else if (const auto history = ActiveChat(controller).history()) {
|
||||||
return history->peer->canWrite();
|
return history->peer->canWrite();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -557,10 +560,11 @@ void AppendEmojiPacks(
|
||||||
|
|
||||||
controller->sessionController()->activeChatValue(
|
controller->sessionController()->activeChatValue(
|
||||||
) | rpl::map([](Dialogs::Key k) {
|
) | rpl::map([](Dialogs::Key k) {
|
||||||
return k.peer()
|
const auto topic = k.topic();
|
||||||
&& k.history()
|
const auto peer = k.peer();
|
||||||
&& k.peer()->canWrite()
|
return peer
|
||||||
&& !RestrictionToSendStickers(k.peer());
|
&& !RestrictionToSendStickers(peer)
|
||||||
|
&& (topic ? topic->canWrite() : peer->canWrite());
|
||||||
}) | rpl::distinct_until_changed(
|
}) | rpl::distinct_until_changed(
|
||||||
) | rpl::start_with_next([=](bool value) {
|
) | rpl::start_with_next([=](bool value) {
|
||||||
[self dismissPopover:nil];
|
[self dismissPopover:nil];
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "apiwrap.h" // ApiWrap::updateStickers()
|
#include "apiwrap.h" // ApiWrap::updateStickers()
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "data/data_peer.h" // PeerData::canWrite()
|
#include "data/data_peer.h" // PeerData::canWrite()
|
||||||
|
#include "data/data_forum_topic.h" // Data::ForumTopic::canWrite()
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/stickers/data_stickers.h" // Stickers::setsRef()
|
#include "data/stickers/data_stickers.h" // Stickers::setsRef()
|
||||||
#include "main/main_domain.h"
|
#include "main/main_domain.h"
|
||||||
|
@ -144,7 +145,11 @@ const auto kAudioItemIdentifier = @"touchbarAudio";
|
||||||
_canApplyMarkdownLast),
|
_canApplyMarkdownLast),
|
||||||
_controller->sessionController()->activeChatValue(
|
_controller->sessionController()->activeChatValue(
|
||||||
) | rpl::map([](Dialogs::Key k) {
|
) | rpl::map([](Dialogs::Key k) {
|
||||||
return k.peer() && k.history() && k.peer()->canWrite();
|
const auto topic = k.topic();
|
||||||
|
const auto peer = k.peer();
|
||||||
|
return topic
|
||||||
|
? topic->canWrite()
|
||||||
|
: (peer && peer->canWrite());
|
||||||
}) | rpl::distinct_until_changed()
|
}) | rpl::distinct_until_changed()
|
||||||
) | rpl::start_with_next([=](
|
) | rpl::start_with_next([=](
|
||||||
bool canApplyMarkdown,
|
bool canApplyMarkdown,
|
||||||
|
|
|
@ -811,6 +811,8 @@ Manager::DisplayOptions Manager::getNotificationOptions(
|
||||||
const auto hideEverything = Core::App().passcodeLocked()
|
const auto hideEverything = Core::App().passcodeLocked()
|
||||||
|| forceHideDetails();
|
|| forceHideDetails();
|
||||||
const auto view = Core::App().settings().notifyView();
|
const auto view = Core::App().settings().notifyView();
|
||||||
|
const auto peer = item ? item->history()->peer.get() : nullptr;
|
||||||
|
const auto topic = item ? item->topic() : nullptr;
|
||||||
|
|
||||||
auto result = DisplayOptions();
|
auto result = DisplayOptions();
|
||||||
result.hideNameAndPhoto = hideEverything
|
result.hideNameAndPhoto = hideEverything
|
||||||
|
@ -820,12 +822,11 @@ Manager::DisplayOptions Manager::getNotificationOptions(
|
||||||
result.hideMarkAsRead = result.hideMessageText
|
result.hideMarkAsRead = result.hideMessageText
|
||||||
|| (type != Data::ItemNotificationType::Message)
|
|| (type != Data::ItemNotificationType::Message)
|
||||||
|| !item
|
|| !item
|
||||||
|| ((item->out() || item->history()->peer->isSelf())
|
|| ((item->out() || peer->isSelf()) && item->isFromScheduled());
|
||||||
&& item->isFromScheduled());
|
|
||||||
result.hideReplyButton = result.hideMarkAsRead
|
result.hideReplyButton = result.hideMarkAsRead
|
||||||
|| !item->history()->peer->canWrite()
|
|| (!peer->canWrite() && (!topic || !topic->canWrite()))
|
||||||
|| item->history()->peer->isBroadcast()
|
|| peer->isBroadcast()
|
||||||
|| (item->history()->peer->slowmodeSecondsLeft() > 0);
|
|| (peer->slowmodeSecondsLeft() > 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1219,7 +1219,7 @@ void PeerMenuShareContactBox(
|
||||||
// There is no async to make weak from controller.
|
// There is no async to make weak from controller.
|
||||||
const auto weak = std::make_shared<QPointer<Ui::BoxContent>>();
|
const auto weak = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||||
auto callback = [=](not_null<PeerData*> peer) {
|
auto callback = [=](not_null<PeerData*> peer) {
|
||||||
if (!peer->canWrite()) {
|
if (!peer->canWrite()) { // #TODO forum forward
|
||||||
navigation->parentController()->show(
|
navigation->parentController()->show(
|
||||||
Ui::MakeInformBox(tr::lng_forward_share_cant()),
|
Ui::MakeInformBox(tr::lng_forward_share_cant()),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
|
@ -1529,10 +1529,10 @@ QPointer<Ui::BoxContent> ShowSendNowMessagesBox(
|
||||||
? tr::lng_scheduled_send_now_many(tr::now, lt_count, items.size())
|
? tr::lng_scheduled_send_now_many(tr::now, lt_count, items.size())
|
||||||
: tr::lng_scheduled_send_now(tr::now);
|
: tr::lng_scheduled_send_now(tr::now);
|
||||||
|
|
||||||
|
const auto list = session->data().idsToItems(items);
|
||||||
const auto error = GetErrorTextForSending(
|
const auto error = GetErrorTextForSending(
|
||||||
history->peer,
|
history->peer,
|
||||||
session->data().idsToItems(items),
|
{ .forward = &list });
|
||||||
TextWithTags());
|
|
||||||
if (!error.isEmpty()) {
|
if (!error.isEmpty()) {
|
||||||
Ui::ShowMultilineToast({
|
Ui::ShowMultilineToast({
|
||||||
.parentOverride = Window::Show(navigation).toastParent(),
|
.parentOverride = Window::Show(navigation).toastParent(),
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 4ba3000a288772752fcf9b41a618ce5df5a185a5
|
Subproject commit c199a1722fae72e254753f3095444a3c82a2a704
|
Loading…
Add table
Reference in a new issue