mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 15:17:07 +02:00
Support separate message type group restrictions.
This commit is contained in:
parent
de5bbf2cb9
commit
554f66f089
64 changed files with 1437 additions and 832 deletions
Telegram
Resources/langs
SourceFiles
apiwrap.cpp
boxes
calls/group
chat_helpers
data
data_channel.cppdata_channel.hdata_chat.cppdata_chat.hdata_chat_participant_status.cppdata_chat_participant_status.hdata_document.cppdata_document.hdata_forum_topic.cppdata_forum_topic.hdata_media_types.cppdata_media_types.hdata_peer.cppdata_peer.hdata_peer_values.cppdata_peer_values.hdata_scheduled_messages.cppdata_thread.cppdata_thread.hdata_user.cppdata_user.h
history
admin_log
history.cpphistory_inner_widget.cpphistory_item.cpphistory_item.hhistory_item_helpers.cpphistory_widget.cpphistory_widget.hview
inline_bots
main/session
mainwidget.cppplatform/mac/touchbar
ui/chat/attach
window
|
@ -3015,6 +3015,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_rights_chat_send_links" = "Embed links";
|
||||
"lng_rights_chat_send_polls" = "Send polls";
|
||||
"lng_rights_chat_add_members" = "Add members";
|
||||
"lng_rights_chat_photos" = "Photos";
|
||||
"lng_rights_chat_videos" = "Video files";
|
||||
"lng_rights_chat_stickers" = "Stickers & GIFs";
|
||||
"lng_rights_chat_music" = "Music";
|
||||
"lng_rights_chat_files" = "Files";
|
||||
"lng_rights_chat_voice_messages" = "Voice messages";
|
||||
"lng_rights_chat_video_messages" = "Video messages";
|
||||
"lng_rights_chat_banned_until_header" = "Restricted until";
|
||||
"lng_rights_chat_banned_forever" = "Forever";
|
||||
"lng_rights_chat_banned_day#one" = "For {count} day";
|
||||
|
@ -3044,21 +3051,36 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_bots_password_confirm_description" = "Please enter your password to confirm the action.";
|
||||
|
||||
"lng_restricted_send_message" = "The admins of this group restricted you from writing here.";
|
||||
"lng_restricted_send_media" = "The admins of this group restricted you from posting media content here.";
|
||||
"lng_restricted_send_photos" = "The admins of this group restricted you from posting photos here.";
|
||||
"lng_restricted_send_videos" = "The admins of this group restricted you from posting video files here.";
|
||||
"lng_restricted_send_music" = "The admins of this group restricted you from posting music here.";
|
||||
"lng_restricted_send_files" = "The admins of this group restricted you from posting files here.";
|
||||
"lng_restricted_send_voice_messages_group" = "The admins of this group restricted you from posting voice messages here.";
|
||||
"lng_restricted_send_video_messages_group" = "The admins of this group restricted you from posting video messages here.";
|
||||
"lng_restricted_send_stickers" = "The admins of this group restricted you from posting stickers here.";
|
||||
"lng_restricted_send_gifs" = "The admins of this group restricted you from posting GIFs here.";
|
||||
"lng_restricted_send_inline" = "The admins of this group restricted you from posting inline content here.";
|
||||
"lng_restricted_send_polls" = "The admins of this group restricted you from posting polls here.";
|
||||
|
||||
"lng_restricted_send_message_until" = "The admins of this group restricted you from writing here until {date}, {time}.";
|
||||
"lng_restricted_send_media_until" = "The admins of this group restricted you from posting media content here until {date}, {time}.";
|
||||
"lng_restricted_send_photos_until" = "The admins of this group restricted you from posting photos here until {date}, {time}.";
|
||||
"lng_restricted_send_videos_until" = "The admins of this group restricted you from posting video files here until {date}, {time}.";
|
||||
"lng_restricted_send_music_until" = "The admins of this group restricted you from posting music here until {date}, {time}.";
|
||||
"lng_restricted_send_files_until" = "The admins of this group restricted you from posting files here until {date}, {time}.";
|
||||
"lng_restricted_send_voice_messages_until" = "The admins of this group restricted you from posting voice messages here until {date}, {time}.";
|
||||
"lng_restricted_send_video_messages_until" = "The admins of this group restricted you from posting video messages here until {date}, {time}.";
|
||||
"lng_restricted_send_stickers_until" = "The admins of this group restricted you from posting stickers here until {date}, {time}.";
|
||||
"lng_restricted_send_gifs_until" = "The admins of this group restricted you from posting GIFs here until {date}, {time}.";
|
||||
"lng_restricted_send_inline_until" = "The admins of this group restricted you from posting inline content here until {date}, {time}.";
|
||||
"lng_restricted_send_polls_until" = "The admins of this group restricted you from posting polls here until {date}, {time}.";
|
||||
|
||||
"lng_restricted_send_message_all" = "Writing messages isn't allowed in this group.";
|
||||
"lng_restricted_send_media_all" = "Posting media content isn't allowed in this group.";
|
||||
"lng_restricted_send_photos_all" = "Posting photos isn't allowed in this group.";
|
||||
"lng_restricted_send_videos_all" = "Posting video files isn't allowed in this group.";
|
||||
"lng_restricted_send_music_all" = "Posting music isn't allowed in this group.";
|
||||
"lng_restricted_send_files_all" = "Posting files isn't allowed in this group.";
|
||||
"lng_restricted_send_voice_messages_all" = "Posting voice messages isn't allowed in this group.";
|
||||
"lng_restricted_send_video_messages_all" = "Posting video messages isn't allowed in this group.";
|
||||
"lng_restricted_send_stickers_all" = "Posting stickers isn't allowed in this group.";
|
||||
"lng_restricted_send_gifs_all" = "Posting GIFs isn't allowed in this group.";
|
||||
"lng_restricted_send_inline_all" = "Posting inline content isn't allowed in this group.";
|
||||
|
@ -3219,7 +3241,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
"lng_admin_log_restricted_until" = "until {date}";
|
||||
"lng_admin_log_banned_view_messages" = "Read messages";
|
||||
"lng_admin_log_banned_send_messages" = "Send messages";
|
||||
"lng_admin_log_banned_send_media" = "Send media";
|
||||
"lng_admin_log_banned_send_photos" = "Send photos";
|
||||
"lng_admin_log_banned_send_videos" = "Send video files";
|
||||
"lng_admin_log_banned_send_music" = "Send music";
|
||||
"lng_admin_log_banned_send_files" = "Send files";
|
||||
"lng_admin_log_banned_send_voice_messages" = "Send voice messages";
|
||||
"lng_admin_log_banned_send_video_messages" = "Send video messages";
|
||||
"lng_admin_log_banned_send_stickers" = "Send stickers & GIFs";
|
||||
"lng_admin_log_banned_embed_links" = "Embed links";
|
||||
"lng_admin_log_banned_send_polls" = "Send polls";
|
||||
|
|
|
@ -3509,7 +3509,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
|||
? action.topicRootId
|
||||
: Data::ForumTopic::kGeneralId;
|
||||
const auto topic = peer->forumTopicFor(topicRootId);
|
||||
if (!(topic ? topic->canWrite() : peer->canWrite())
|
||||
if (!(topic ? Data::CanSendTexts(topic) : Data::CanSendTexts(peer))
|
||||
|| Api::SendDice(message)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -534,9 +534,8 @@ auto ChooseRecipientBoxController::createRow(
|
|||
const auto peer = history->peer;
|
||||
const auto skip = _filter
|
||||
? !_filter(history)
|
||||
: ((peer->isBroadcast() && !peer->canWrite())
|
||||
|| (peer->isUser() && !peer->canWrite())
|
||||
|| peer->isRepliesChat());
|
||||
: ((peer->isBroadcast() && !Data::CanSendAnything(peer))
|
||||
|| (peer->isUser() && !Data::CanSendAnything(peer)));
|
||||
return skip ? nullptr : std::make_unique<Row>(history);
|
||||
}
|
||||
|
||||
|
@ -752,6 +751,6 @@ std::unique_ptr<PeerListRow> ChooseTopicBoxController::createSearchRow(
|
|||
|
||||
auto ChooseTopicBoxController::createRow(not_null<Data::ForumTopic*> topic)
|
||||
-> std::unique_ptr<Row> {
|
||||
const auto skip = _filter ? !_filter(topic) : !topic->canWrite();
|
||||
const auto skip = _filter && !_filter(topic);
|
||||
return skip ? nullptr : std::make_unique<Row>(topic);
|
||||
};
|
||||
|
|
|
@ -1200,11 +1200,14 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox(
|
|||
(*box)->closeBox();
|
||||
}
|
||||
};
|
||||
auto filterCallback = [](not_null<Data::Thread*> thread) {
|
||||
return Data::CanSendTexts(thread);
|
||||
};
|
||||
auto object = Box<ShareBox>(ShareBox::Descriptor{
|
||||
.session = &peer->session(),
|
||||
.copyCallback = std::move(copyCallback),
|
||||
.submitCallback = std::move(submitCallback),
|
||||
.filterCallback = [](auto thread) { return thread->canWrite(); },
|
||||
.filterCallback = std::move(filterCallback),
|
||||
});
|
||||
*box = Ui::MakeWeak(object.data());
|
||||
return object;
|
||||
|
|
|
@ -123,23 +123,26 @@ auto Dependencies(ChatRestrictions)
|
|||
{ Flag::SendInline, Flag::SendStickers },
|
||||
{ Flag::SendStickers, Flag::SendInline },
|
||||
|
||||
// stickers -> send_messages
|
||||
{ Flag::SendStickers, Flag::SendMessages },
|
||||
// embed_links -> send_plain
|
||||
{ Flag::EmbedLinks, Flag::SendOther },
|
||||
|
||||
// embed_links -> send_messages
|
||||
{ Flag::EmbedLinks, Flag::SendMessages },
|
||||
|
||||
// send_media -> send_messages
|
||||
{ Flag::SendMedia, Flag::SendMessages },
|
||||
|
||||
// send_polls -> send_messages
|
||||
{ Flag::SendPolls, Flag::SendMessages },
|
||||
|
||||
// send_messages -> view_messages
|
||||
{ Flag::SendMessages, Flag::ViewMessages },
|
||||
// send_* -> view_messages
|
||||
{ Flag::SendStickers, Flag::ViewMessages },
|
||||
{ Flag::SendGifs, Flag::ViewMessages },
|
||||
{ Flag::SendGames, Flag::ViewMessages },
|
||||
{ Flag::SendInline, Flag::ViewMessages },
|
||||
{ Flag::SendPolls, Flag::ViewMessages },
|
||||
{ Flag::SendPhotos, Flag::ViewMessages },
|
||||
{ Flag::SendVideos, Flag::ViewMessages },
|
||||
{ Flag::SendVideoMessages, Flag::ViewMessages },
|
||||
{ Flag::SendMusic, Flag::ViewMessages },
|
||||
{ Flag::SendVoiceMessages, Flag::ViewMessages },
|
||||
{ Flag::SendFiles, Flag::ViewMessages },
|
||||
{ Flag::SendOther, Flag::ViewMessages },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
ChatRestrictions NegateRestrictions(ChatRestrictions value) {
|
||||
using Flag = ChatRestriction;
|
||||
|
||||
|
@ -154,10 +157,15 @@ ChatRestrictions NegateRestrictions(ChatRestrictions value) {
|
|||
| Flag::SendGames
|
||||
| Flag::SendGifs
|
||||
| Flag::SendInline
|
||||
| Flag::SendMedia
|
||||
| Flag::SendMessages
|
||||
| Flag::SendPolls
|
||||
| Flag::SendStickers);
|
||||
| Flag::SendStickers
|
||||
| Flag::SendPhotos
|
||||
| Flag::SendVideos
|
||||
| Flag::SendVideoMessages
|
||||
| Flag::SendMusic
|
||||
| Flag::SendVoiceMessages
|
||||
| Flag::SendFiles
|
||||
| Flag::SendOther);
|
||||
}
|
||||
|
||||
auto Dependencies(ChatAdminRights)
|
||||
|
@ -722,13 +730,20 @@ void EditPeerPermissionsBox::addBannedButtons(
|
|||
std::vector<RestrictionLabel> RestrictionLabels(
|
||||
Data::RestrictionsSetOptions options) {
|
||||
using Flag = ChatRestriction;
|
||||
|
||||
auto result = std::vector<RestrictionLabel>{
|
||||
{ Flag::SendMessages, tr::lng_rights_chat_send_text(tr::now) },
|
||||
{ Flag::SendMedia, tr::lng_rights_chat_send_media(tr::now) },
|
||||
{ Flag::SendOther, tr::lng_rights_chat_send_text(tr::now) },
|
||||
// { Flag::SendMedia, tr::lng_rights_chat_send_media(tr::now) },
|
||||
{ Flag::SendPhotos, tr::lng_rights_chat_photos(tr::now) },
|
||||
{ Flag::SendVideos, tr::lng_rights_chat_videos(tr::now) },
|
||||
{ Flag::SendVideoMessages, tr::lng_rights_chat_video_messages(tr::now) },
|
||||
{ Flag::SendMusic, tr::lng_rights_chat_music(tr::now) },
|
||||
{ Flag::SendVoiceMessages, tr::lng_rights_chat_voice_messages(tr::now) },
|
||||
{ Flag::SendFiles, tr::lng_rights_chat_files(tr::now) },
|
||||
{ Flag::SendStickers
|
||||
| Flag::SendGifs
|
||||
| Flag::SendGames
|
||||
| Flag::SendInline, tr::lng_rights_chat_send_stickers(tr::now) },
|
||||
| Flag::SendInline, tr::lng_rights_chat_stickers(tr::now) },
|
||||
{ Flag::EmbedLinks, tr::lng_rights_chat_send_links(tr::now) },
|
||||
{ Flag::SendPolls, tr::lng_rights_chat_send_polls(tr::now) },
|
||||
{ Flag::AddParticipants, tr::lng_rights_chat_add_members(tr::now) },
|
||||
|
|
|
@ -114,6 +114,41 @@ rpl::producer<QString> FieldPlaceholder(
|
|||
|
||||
} // namespace
|
||||
|
||||
SendFilesLimits DefaultLimitsForPeer(not_null<PeerData*> peer) {
|
||||
using Flag = SendFilesAllow;
|
||||
using Restriction = ChatRestriction;
|
||||
const auto allowByRestriction = [&](Restriction check, Flag allow) {
|
||||
return Data::RestrictionError(peer, check) ? Flag() : allow;
|
||||
};
|
||||
return Flag()
|
||||
| (peer->slowmodeApplied() ? Flag::OnlyOne : Flag())
|
||||
| (Data::AllowEmojiWithoutPremium(peer)
|
||||
? Flag::EmojiWithoutPremium
|
||||
: Flag())
|
||||
| allowByRestriction(Restriction::SendPhotos, Flag::Photos)
|
||||
| allowByRestriction(Restriction::SendVideos, Flag::Videos)
|
||||
| allowByRestriction(Restriction::SendMusic, Flag::Music)
|
||||
| allowByRestriction(Restriction::SendFiles, Flag::Files)
|
||||
| allowByRestriction(Restriction::SendStickers, Flag::Stickers)
|
||||
| allowByRestriction(Restriction::SendGifs, Flag::Gifs)
|
||||
| allowByRestriction(Restriction::SendOther, Flag::Texts);
|
||||
}
|
||||
|
||||
SendFilesCheck DefaultCheckForPeer(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer) {
|
||||
return [=](
|
||||
const Ui::PreparedFile &file,
|
||||
bool compress,
|
||||
bool silent) {
|
||||
const auto error = Data::FileRestrictionError(peer, file, compress);
|
||||
if (error && !silent) {
|
||||
controller->showToast({ *error });
|
||||
}
|
||||
return !error.has_value();
|
||||
};
|
||||
}
|
||||
|
||||
SendFilesBox::Block::Block(
|
||||
not_null<QWidget*> parent,
|
||||
not_null<std::vector<Ui::PreparedFile>*> items,
|
||||
|
@ -289,16 +324,17 @@ SendFilesBox::SendFilesBox(
|
|||
not_null<Window::SessionController*> controller,
|
||||
Ui::PreparedList &&list,
|
||||
const TextWithTags &caption,
|
||||
not_null<PeerData*> peer,
|
||||
SendFilesLimits limits,
|
||||
SendFilesCheck check,
|
||||
Api::SendType sendType,
|
||||
SendMenu::Type sendMenuType)
|
||||
: _controller(controller)
|
||||
, _sendType(sendType)
|
||||
, _titleHeight(st::boxTitleHeight)
|
||||
, _list(std::move(list))
|
||||
, _sendLimit(peer->slowmodeApplied() ? SendLimit::One : SendLimit::Many)
|
||||
, _limits(limits)
|
||||
, _sendMenuType(sendMenuType)
|
||||
, _allowEmojiWithoutPremium(Data::AllowEmojiWithoutPremium(peer))
|
||||
, _check(std::move(check))
|
||||
, _caption(this, st::confirmCaptionArea, Ui::InputField::Mode::MultiLine)
|
||||
, _prefilledCaptionText(std::move(caption))
|
||||
, _scroll(this, st::boxScroll)
|
||||
|
@ -419,6 +455,11 @@ void SendFilesBox::refreshAllAfterChanges(int fromItem, Fn<void()> perform) {
|
|||
{
|
||||
auto sendWay = _sendWay.current();
|
||||
sendWay.setHasCompressedStickers(_list.hasSticker());
|
||||
if (_limits & SendFilesAllow::OnlyOne) {
|
||||
if (_list.files.size() > 1) {
|
||||
sendWay.setGroupFiles(true);
|
||||
}
|
||||
}
|
||||
_sendWay = sendWay;
|
||||
}
|
||||
_inner->resizeToWidth(st::boxWideWidth);
|
||||
|
@ -429,7 +470,8 @@ void SendFilesBox::refreshAllAfterChanges(int fromItem, Fn<void()> perform) {
|
|||
void SendFilesBox::openDialogToAddFileToAlbum() {
|
||||
const auto toastParent = Ui::BoxShow(this).toastParent();
|
||||
const auto checkResult = [=](const Ui::PreparedList &list) {
|
||||
if (_sendLimit != SendLimit::One) {
|
||||
if (_check)
|
||||
if (!(_limits & SendFilesAllow::OnlyOne)) {
|
||||
return true;
|
||||
} else if (!_list.canBeSentInSlowmodeWith(list)) {
|
||||
Ui::Toast::Show(toastParent, tr::lng_slowmode_no_many(tr::now));
|
||||
|
@ -555,20 +597,36 @@ void SendFilesBox::initSendWay() {
|
|||
_sendWay = [&] {
|
||||
auto result = Core::App().settings().sendFilesWay();
|
||||
result.setHasCompressedStickers(_list.hasSticker());
|
||||
if (_sendLimit == SendLimit::One) {
|
||||
if ((_limits & SendFilesAllow::OnlyOne)
|
||||
&& (_list.files.size() > 1)) {
|
||||
result.setGroupFiles(true);
|
||||
return result;
|
||||
} else if (_list.overrideSendImagesAsPhotos == false) {
|
||||
result.setSendImagesAsPhotos(false);
|
||||
}
|
||||
if (_list.overrideSendImagesAsPhotos == false) {
|
||||
if (!(_limits & SendFilesAllow::OnlyOne)
|
||||
|| !_list.hasSticker()) {
|
||||
result.setSendImagesAsPhotos(false);
|
||||
}
|
||||
return result;
|
||||
} else if (_list.overrideSendImagesAsPhotos == true) {
|
||||
result.setSendImagesAsPhotos(true);
|
||||
const auto silent = true;
|
||||
if (!checkWithWay(result, silent)) {
|
||||
result.setSendImagesAsPhotos(false);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const auto silent = true;
|
||||
if (!checkWithWay(result, silent)) {
|
||||
result.setSendImagesAsPhotos(!result.sendImagesAsPhotos());
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
_sendWay.changes(
|
||||
) | rpl::start_with_next([=](SendFilesWay value) {
|
||||
const auto hidden = [&] {
|
||||
return !_caption || _caption->isHidden();
|
||||
};
|
||||
const auto was = hidden();
|
||||
updateCaptionPlaceholder();
|
||||
updateEmojiPanelGeometry();
|
||||
for (auto &block : _blocks) {
|
||||
|
@ -577,6 +635,10 @@ void SendFilesBox::initSendWay() {
|
|||
if (!hasSendMenu()) {
|
||||
refreshButtons();
|
||||
}
|
||||
if (was != hidden()) {
|
||||
updateBoxSize();
|
||||
updateControlsGeometry();
|
||||
}
|
||||
setInnerFocus();
|
||||
}, lifetime());
|
||||
}
|
||||
|
@ -589,7 +651,8 @@ void SendFilesBox::updateCaptionPlaceholder() {
|
|||
if (!_list.canAddCaption(
|
||||
way.groupFiles() && way.sendImagesAsPhotos(),
|
||||
way.sendImagesAsPhotos())
|
||||
&& _sendLimit == SendLimit::One) {
|
||||
&& ((_limits & SendFilesAllow::OnlyOne)
|
||||
|| !(_limits & SendFilesAllow::Texts))) {
|
||||
_caption->hide();
|
||||
if (_emojiToggle) {
|
||||
_emojiToggle->hide();
|
||||
|
@ -695,8 +758,8 @@ void SendFilesBox::pushBlock(int from, int till) {
|
|||
_list.files[index] = std::move(list.files.front());
|
||||
});
|
||||
};
|
||||
const auto checkResult = [=](const Ui::PreparedList &list) {
|
||||
if (_sendLimit != SendLimit::One) {
|
||||
const auto checkSlowmode = [=](const Ui::PreparedList &list) {
|
||||
if (list.files.empty() || !(_limits & SendFilesAllow::OnlyOne)) {
|
||||
return true;
|
||||
}
|
||||
auto removing = std::move(_list.files[index]);
|
||||
|
@ -713,6 +776,37 @@ void SendFilesBox::pushBlock(int from, int till) {
|
|||
}
|
||||
return true;
|
||||
};
|
||||
const auto checkRights = [=](const Ui::PreparedList &list) {
|
||||
if (list.files.empty()) {
|
||||
return true;
|
||||
}
|
||||
auto removing = std::move(_list.files[index]);
|
||||
std::swap(_list.files[index], _list.files.back());
|
||||
_list.files.pop_back();
|
||||
auto way = _sendWay.current();
|
||||
const auto has = _list.hasSticker()
|
||||
|| list.files.front().isSticker();
|
||||
way.setHasCompressedStickers(has);
|
||||
if (_limits & SendFilesAllow::OnlyOne) {
|
||||
way.setGroupFiles(true);
|
||||
}
|
||||
const auto silent = true;
|
||||
if (!checkWith(list, way, silent)
|
||||
&& (!(_limits & SendFilesAllow::OnlyOne) || !has)) {
|
||||
way.setSendImagesAsPhotos(!way.sendImagesAsPhotos());
|
||||
}
|
||||
const auto result = checkWith(list, way);
|
||||
_list.files.push_back(std::move(removing));
|
||||
std::swap(_list.files[index], _list.files.back());
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
_sendWay = way;
|
||||
return true;
|
||||
};
|
||||
const auto checkResult = [=](const Ui::PreparedList &list) {
|
||||
return checkSlowmode(list) && checkRights(list);
|
||||
};
|
||||
const auto callback = [=](FileDialog::OpenResult &&result) {
|
||||
const auto premium = _controller->session().premium();
|
||||
FileDialogCallback(
|
||||
|
@ -767,7 +861,7 @@ void SendFilesBox::setupSendWayControls() {
|
|||
_sendImagesAsPhotos.create(
|
||||
this,
|
||||
tr::lng_send_compressed(tr::now),
|
||||
asPhotosFirst,
|
||||
_sendWay.current().sendImagesAsPhotos(),
|
||||
st::defaultBoxCheckbox);
|
||||
|
||||
_sendWay.changes(
|
||||
|
@ -777,17 +871,35 @@ void SendFilesBox::setupSendWayControls() {
|
|||
}, lifetime());
|
||||
|
||||
_groupFiles->checkedChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
auto sendWay = _sendWay.current();
|
||||
sendWay.setGroupFiles(_groupFiles->checked());
|
||||
_sendWay = sendWay;
|
||||
if (sendWay.groupFiles() == checked) {
|
||||
return;
|
||||
}
|
||||
sendWay.setGroupFiles(checked);
|
||||
if (checkWithWay(sendWay)) {
|
||||
_sendWay = sendWay;
|
||||
} else {
|
||||
Ui::PostponeCall(_groupFiles.data(), [=] {
|
||||
_groupFiles->setChecked(!checked);
|
||||
});
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
_sendImagesAsPhotos->checkedChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
) | rpl::start_with_next([=](bool checked) {
|
||||
auto sendWay = _sendWay.current();
|
||||
sendWay.setSendImagesAsPhotos(_sendImagesAsPhotos->checked());
|
||||
_sendWay = sendWay;
|
||||
if (sendWay.sendImagesAsPhotos() == checked) {
|
||||
return;
|
||||
}
|
||||
sendWay.setSendImagesAsPhotos(checked);
|
||||
if (checkWithWay(sendWay)) {
|
||||
_sendWay = sendWay;
|
||||
} else {
|
||||
Ui::PostponeCall(_sendImagesAsPhotos.data(), [=] {
|
||||
_sendImagesAsPhotos->setChecked(!checked);
|
||||
});
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
_wayRemember.create(
|
||||
|
@ -811,8 +923,29 @@ void SendFilesBox::setupSendWayControls() {
|
|||
st::editMediaHintLabel);
|
||||
}
|
||||
|
||||
bool SendFilesBox::checkWithWay(Ui::SendFilesWay way, bool silent) const {
|
||||
return checkWith({}, way, silent);
|
||||
}
|
||||
|
||||
bool SendFilesBox::checkWith(
|
||||
const Ui::PreparedList &added,
|
||||
Ui::SendFilesWay way,
|
||||
bool silent) const {
|
||||
if (!_check) {
|
||||
return true;
|
||||
}
|
||||
const auto compress = way.sendImagesAsPhotos();
|
||||
auto &already = _list.files;
|
||||
for (const auto &file : ranges::views::concat(already, added.files)) {
|
||||
if (!_check(file, compress, silent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SendFilesBox::updateSendWayControls() {
|
||||
const auto onlyOne = (_sendLimit == SendLimit::One);
|
||||
const auto onlyOne = (_limits & SendFilesAllow::OnlyOne);
|
||||
_groupFiles->setVisible(_list.hasGroupOption(onlyOne));
|
||||
_sendImagesAsPhotos->setVisible(
|
||||
_list.hasSendImagesAsPhotosOption(onlyOne));
|
||||
|
@ -828,7 +961,7 @@ void SendFilesBox::updateSendWayControls() {
|
|||
|
||||
void SendFilesBox::setupCaption() {
|
||||
const auto allow = [=](const auto&) {
|
||||
return _allowEmojiWithoutPremium;
|
||||
return (_limits & SendFilesAllow::EmojiWithoutPremium);
|
||||
};
|
||||
InitMessageFieldHandlers(
|
||||
_controller,
|
||||
|
@ -899,7 +1032,7 @@ void SendFilesBox::setupEmojiPanel() {
|
|||
st::emojiPanMinHeight);
|
||||
_emojiPanel->hide();
|
||||
_emojiPanel->selector()->setAllowEmojiWithoutPremium(
|
||||
_allowEmojiWithoutPremium);
|
||||
_limits & SendFilesAllow::EmojiWithoutPremium);
|
||||
_emojiPanel->selector()->emojiChosen(
|
||||
) | rpl::start_with_next([=](ChatHelpers::EmojiChosen data) {
|
||||
Ui::InsertEmojiAtCursor(_caption->textCursor(), data.emoji);
|
||||
|
@ -910,7 +1043,7 @@ void SendFilesBox::setupEmojiPanel() {
|
|||
if (info
|
||||
&& info->setType == Data::StickersType::Emoji
|
||||
&& !_controller->session().premium()
|
||||
&& !_allowEmojiWithoutPremium) {
|
||||
&& !(_limits & SendFilesAllow::EmojiWithoutPremium)) {
|
||||
ShowPremiumPreviewBox(
|
||||
_controller,
|
||||
PremiumPreview::AnimatedEmoji);
|
||||
|
@ -1026,7 +1159,20 @@ void SendFilesBox::addFile(Ui::PreparedFile &&file) {
|
|||
// canBeSentInSlowmode checks for non empty filesToProcess.
|
||||
auto saved = base::take(_list.filesToProcess);
|
||||
_list.files.push_back(std::move(file));
|
||||
if (_sendLimit == SendLimit::One && !_list.canBeSentInSlowmode()) {
|
||||
const auto lastOk = [&] {
|
||||
auto way = _sendWay.current();
|
||||
if (_limits & SendFilesAllow::OnlyOne) {
|
||||
way.setGroupFiles(true);
|
||||
if (!_list.canBeSentInSlowmode()) {
|
||||
return false;
|
||||
}
|
||||
} else if (!checkWithWay(way)) {
|
||||
return false;
|
||||
}
|
||||
_sendWay = way;
|
||||
return true;
|
||||
}();
|
||||
if (!lastOk) {
|
||||
_list.files.pop_back();
|
||||
}
|
||||
_list.filesToProcess = std::move(saved);
|
||||
|
@ -1058,7 +1204,7 @@ void SendFilesBox::refreshTitleText() {
|
|||
|
||||
void SendFilesBox::updateBoxSize() {
|
||||
auto footerHeight = 0;
|
||||
if (_caption) {
|
||||
if (_caption && !_caption->isHidden()) {
|
||||
footerHeight += st::boxPhotoCaptionSkip + _caption->height();
|
||||
}
|
||||
const auto pairs = std::array<std::pair<RpWidget*, int>, 4>{ {
|
||||
|
@ -1113,7 +1259,7 @@ void SendFilesBox::resizeEvent(QResizeEvent *e) {
|
|||
|
||||
void SendFilesBox::updateControlsGeometry() {
|
||||
auto bottom = height();
|
||||
if (_caption) {
|
||||
if (_caption && !_caption->isHidden()) {
|
||||
_caption->resize(st::sendMediaPreviewSize, _caption->height());
|
||||
_caption->moveToLeft(
|
||||
st::boxPhotoPadding.left(),
|
||||
|
|
|
@ -7,7 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <rpl/variable.h>
|
||||
#include "base/flags.h"
|
||||
#include "boxes/abstract_box.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
|
@ -48,6 +48,30 @@ namespace SendMenu {
|
|||
enum class Type;
|
||||
} // namespace SendMenu
|
||||
|
||||
enum class SendFilesAllow {
|
||||
OnlyOne = (1 << 0),
|
||||
Photos = (1 << 1),
|
||||
Videos = (1 << 2),
|
||||
Music = (1 << 3),
|
||||
Files = (1 << 4),
|
||||
Stickers = (1 << 5),
|
||||
Gifs = (1 << 6),
|
||||
EmojiWithoutPremium = (1 << 7),
|
||||
Texts = (1 << 8),
|
||||
};
|
||||
inline constexpr bool is_flag_type(SendFilesAllow) { return true; }
|
||||
using SendFilesLimits = base::flags<SendFilesAllow>;
|
||||
|
||||
using SendFilesCheck = Fn<bool(
|
||||
const Ui::PreparedFile &file,
|
||||
bool compress,
|
||||
bool silent)>;
|
||||
|
||||
[[nodiscard]] SendFilesLimits DefaultLimitsForPeer(not_null<PeerData*> peer);
|
||||
[[nodiscard]] SendFilesCheck DefaultCheckForPeer(
|
||||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
class SendFilesBox : public Ui::BoxContent {
|
||||
public:
|
||||
enum class SendLimit {
|
||||
|
@ -59,7 +83,8 @@ public:
|
|||
not_null<Window::SessionController*> controller,
|
||||
Ui::PreparedList &&list,
|
||||
const TextWithTags &caption,
|
||||
not_null<PeerData*> peer,
|
||||
SendFilesLimits limits,
|
||||
SendFilesCheck check,
|
||||
Api::SendType sendType,
|
||||
SendMenu::Type sendMenuType);
|
||||
|
||||
|
@ -126,6 +151,13 @@ private:
|
|||
[[nodiscard]] bool hasSendMenu() const;
|
||||
[[nodiscard]] bool hasSpoilerMenu() const;
|
||||
[[nodiscard]] bool allWithSpoilers();
|
||||
[[nodiscard]] bool checkWithWay(
|
||||
Ui::SendFilesWay way,
|
||||
bool silent = false) const;
|
||||
[[nodiscard]] bool checkWith(
|
||||
const Ui::PreparedList &added,
|
||||
Ui::SendFilesWay way,
|
||||
bool silent = false) const;
|
||||
void addMenuButton();
|
||||
void applyBlockChanges();
|
||||
void toggleSpoilers(bool enabled);
|
||||
|
@ -177,10 +209,10 @@ private:
|
|||
Ui::PreparedList _list;
|
||||
std::optional<int> _removingIndex;
|
||||
|
||||
SendLimit _sendLimit = SendLimit::Many;
|
||||
SendFilesLimits _limits = {};
|
||||
SendMenu::Type _sendMenuType = SendMenu::Type();
|
||||
bool _allowEmojiWithoutPremium = false;
|
||||
|
||||
SendFilesCheck _check;
|
||||
Fn<void(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
|
|
|
@ -1120,10 +1120,14 @@ void ShareBox::Inner::chooseForumTopic(not_null<Data::Forum*> forum) {
|
|||
box->closeBox();
|
||||
}, box->lifetime());
|
||||
};
|
||||
auto filter = [=](not_null<Data::ForumTopic*> topic) {
|
||||
return guard && _descriptor.filterCallback(topic);
|
||||
};
|
||||
auto box = Box<PeerListBox>(
|
||||
std::make_unique<ChooseTopicBoxController>(
|
||||
forum,
|
||||
std::move(chosen)),
|
||||
std::move(chosen),
|
||||
std::move(filter)),
|
||||
std::move(initBox));
|
||||
*weak = box.data();
|
||||
_show->showBox(std::move(box));
|
||||
|
@ -1507,8 +1511,12 @@ void FastShareMessage(
|
|||
}
|
||||
};
|
||||
|
||||
auto filterCallback = [isGame](not_null<Data::Thread*> thread) {
|
||||
return thread->canWrite()
|
||||
const auto requiredRight = item->requiredSendRight();
|
||||
const auto requiresInline = item->requiresSendInlineRight();
|
||||
auto filterCallback = [=](not_null<Data::Thread*> thread) {
|
||||
return Data::CanSend(thread, requiredRight)
|
||||
&& (!requiresInline
|
||||
|| Data::CanSend(thread, ChatRestriction::SendInline))
|
||||
&& (!isGame || !thread->peer()->isBroadcast());
|
||||
};
|
||||
auto copyLinkCallback = canCopyLink
|
||||
|
|
|
@ -1639,7 +1639,7 @@ void Members::setupAddMember(not_null<GroupCall*> call) {
|
|||
return rpl::single(false) | rpl::type_erased();
|
||||
}
|
||||
return rpl::combine(
|
||||
Data::CanWriteValue(peer, false),
|
||||
Data::CanSendValue(peer, ChatRestriction::SendOther, false),
|
||||
_call->joinAsValue()
|
||||
) | rpl::map([=](bool can, not_null<PeerData*> joinAs) {
|
||||
return can && joinAs->isSelf();
|
||||
|
|
|
@ -845,7 +845,7 @@ void Panel::setupMembers() {
|
|||
_members->addMembersRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
if (!_peer->isBroadcast()
|
||||
&& _peer->canWrite(false)
|
||||
&& Data::CanSend(_peer, ChatRestriction::SendOther, false)
|
||||
&& _call->joinAs()->isSelf()) {
|
||||
addMembers();
|
||||
} else if (const auto channel = _peer->asChannel()) {
|
||||
|
|
|
@ -194,7 +194,7 @@ object_ptr<ShareBox> ShareInviteLinkBox(
|
|||
showToast(tr::lng_share_done(tr::now));
|
||||
};
|
||||
auto filterCallback = [](not_null<Data::Thread*> thread) {
|
||||
return thread->canWrite();
|
||||
return Data::CanSend(thread, ChatRestriction::SendOther);
|
||||
};
|
||||
|
||||
const auto scheduleStyle = [&] {
|
||||
|
|
|
@ -388,7 +388,9 @@ TabbedSelector::TabbedSelector(
|
|||
_tabsSlider->raise();
|
||||
}
|
||||
|
||||
if (hasStickersTab() || hasGifsTab()) {
|
||||
if (hasStickersTab()
|
||||
|| hasGifsTab()
|
||||
|| (hasEmojiTab() && _mode == Mode::Full)) {
|
||||
session().changes().peerUpdates(
|
||||
Data::PeerUpdate::Flag::Rights
|
||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||
|
@ -892,6 +894,14 @@ void TabbedSelector::checkRestrictedPeer() {
|
|||
? Data::RestrictionError(
|
||||
_currentPeer,
|
||||
ChatRestriction::SendGifs)
|
||||
: (_currentTabType == SelectorTab::Emoji && _mode == Mode::Full)
|
||||
? (Data::RestrictionError(
|
||||
_currentPeer,
|
||||
ChatRestriction::SendInline)
|
||||
? Data::RestrictionError(
|
||||
_currentPeer,
|
||||
ChatRestriction::SendOther)
|
||||
: std::nullopt)
|
||||
: std::nullopt;
|
||||
if (error) {
|
||||
if (!_restrictedLabel) {
|
||||
|
|
|
@ -321,13 +321,18 @@ ChatRestrictionsInfo ChannelData::KickedRestrictedRights(
|
|||
not_null<PeerData*> participant) {
|
||||
using Flag = ChatRestriction;
|
||||
const auto flags = Flag::ViewMessages
|
||||
| Flag::SendMessages
|
||||
| Flag::SendMedia
|
||||
| Flag::EmbedLinks
|
||||
| Flag::SendStickers
|
||||
| Flag::SendGifs
|
||||
| Flag::SendGames
|
||||
| Flag::SendInline;
|
||||
| Flag::SendInline
|
||||
| Flag::SendPhotos
|
||||
| Flag::SendVideos
|
||||
| Flag::SendVideoMessages
|
||||
| Flag::SendMusic
|
||||
| Flag::SendVoiceMessages
|
||||
| Flag::SendFiles
|
||||
| Flag::SendOther
|
||||
| Flag::EmbedLinks;
|
||||
return ChatRestrictionsInfo(
|
||||
(participant->isUser() ? flags : Flag::ViewMessages),
|
||||
std::numeric_limits<int32>::max());
|
||||
|
@ -549,10 +554,6 @@ bool ChannelData::canAddMembers() const {
|
|||
: ((adminRights() & AdminRight::InviteByLinkOrAdd) || amCreator());
|
||||
}
|
||||
|
||||
bool ChannelData::canSendPolls() const {
|
||||
return canWrite() && !amRestricted(ChatRestriction::SendPolls);
|
||||
}
|
||||
|
||||
bool ChannelData::canAddAdmins() const {
|
||||
return amCreator()
|
||||
|| (adminRights() & AdminRight::AddAdmins);
|
||||
|
@ -563,18 +564,6 @@ bool ChannelData::canPublish() const {
|
|||
|| (adminRights() & AdminRight::PostMessages);
|
||||
}
|
||||
|
||||
bool ChannelData::canWrite(bool checkForForum) const {
|
||||
// Duplicated in Data::CanWriteValue().
|
||||
const auto allowed = amIn()
|
||||
|| ((flags() & Flag::HasLink) && !(flags() & Flag::JoinToWrite));
|
||||
const auto forumRestriction = checkForForum && isForum();
|
||||
return allowed
|
||||
&& !forumRestriction
|
||||
&& (canPublish()
|
||||
|| (!isBroadcast()
|
||||
&& !amRestricted(Restriction::SendMessages)));
|
||||
}
|
||||
|
||||
bool ChannelData::allowsForwarding() const {
|
||||
return !(flags() & Flag::NoForwards);
|
||||
}
|
||||
|
|
|
@ -318,7 +318,6 @@ public:
|
|||
void setDefaultRestrictions(ChatRestrictions rights);
|
||||
|
||||
// Like in ChatData.
|
||||
[[nodiscard]] bool canWrite(bool checkForForum = true) const;
|
||||
[[nodiscard]] bool allowsForwarding() const;
|
||||
[[nodiscard]] bool canEditInformation() const;
|
||||
[[nodiscard]] bool canEditPermissions() const;
|
||||
|
@ -327,7 +326,6 @@ public:
|
|||
[[nodiscard]] bool canAddMembers() const;
|
||||
[[nodiscard]] bool canAddAdmins() const;
|
||||
[[nodiscard]] bool canBanMembers() const;
|
||||
[[nodiscard]] bool canSendPolls() const;
|
||||
[[nodiscard]] bool anyoneCanAddMembers() const;
|
||||
|
||||
[[nodiscard]] bool canEditMessages() const;
|
||||
|
|
|
@ -63,11 +63,6 @@ ChatAdminRightsInfo ChatData::defaultAdminRights(not_null<UserData*> user) {
|
|||
| (isCreator ? Flag::AddAdmins : Flag(0)));
|
||||
}
|
||||
|
||||
bool ChatData::canWrite() const {
|
||||
// Duplicated in Data::CanWriteValue().
|
||||
return amIn() && !amRestricted(ChatRestriction::SendMessages);
|
||||
}
|
||||
|
||||
bool ChatData::allowsForwarding() const {
|
||||
return !(flags() & Flag::NoForwards);
|
||||
}
|
||||
|
@ -99,10 +94,6 @@ bool ChatData::canAddMembers() const {
|
|||
return amIn() && !amRestricted(ChatRestriction::AddParticipants);
|
||||
}
|
||||
|
||||
bool ChatData::canSendPolls() const {
|
||||
return amIn() && !amRestricted(ChatRestriction::SendPolls);
|
||||
}
|
||||
|
||||
bool ChatData::canAddAdmins() const {
|
||||
return amIn() && amCreator();
|
||||
}
|
||||
|
|
|
@ -100,7 +100,6 @@ public:
|
|||
not_null<UserData*> user);
|
||||
|
||||
// Like in ChannelData.
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
[[nodiscard]] bool allowsForwarding() const;
|
||||
[[nodiscard]] bool canEditInformation() const;
|
||||
[[nodiscard]] bool canEditPermissions() const;
|
||||
|
@ -110,7 +109,6 @@ public:
|
|||
[[nodiscard]] bool canAddMembers() const;
|
||||
[[nodiscard]] bool canAddAdmins() const;
|
||||
[[nodiscard]] bool canBanMembers() const;
|
||||
[[nodiscard]] bool canSendPolls() const;
|
||||
[[nodiscard]] bool anyoneCanAddMembers() const;
|
||||
|
||||
void applyEditAdmin(not_null<UserData*> user, bool isAdmin);
|
||||
|
|
|
@ -7,7 +7,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "data/data_chat_participant_status.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_user.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -53,4 +61,313 @@ std::vector<ChatRestrictions> ListOfRestrictions(
|
|||
| ranges::to_vector;
|
||||
}
|
||||
|
||||
ChatRestrictions AllSendRestrictions() {
|
||||
constexpr auto result = [] {
|
||||
auto result = ChatRestrictions();
|
||||
for (const auto right : AllSendRestrictionsList()) {
|
||||
result |= right;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
ChatRestrictions FilesSendRestrictions() {
|
||||
constexpr auto result = [] {
|
||||
auto result = ChatRestrictions();
|
||||
for (const auto right : FilesSendRestrictionsList()) {
|
||||
result |= right;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
ChatRestrictions TabbedPanelSendRestrictions() {
|
||||
constexpr auto result = [] {
|
||||
auto result = ChatRestrictions();
|
||||
for (const auto right : TabbedPanelSendRestrictionsList()) {
|
||||
result |= right;
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Duplicated in CanSendAnyOfValue().
|
||||
bool CanSendAnyOf(
|
||||
not_null<Thread*> thread,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums) {
|
||||
const auto peer = thread->peer();
|
||||
const auto topic = thread->asTopic();
|
||||
return CanSendAnyOf(peer, rights, forbidInForums && !topic)
|
||||
&& (!topic || !topic->closed() || topic->canToggleClosed());
|
||||
}
|
||||
|
||||
// Duplicated in CanSendAnyOfValue().
|
||||
bool CanSendAnyOf(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->isInaccessible() || user->isRepliesChat()) {
|
||||
return false;
|
||||
} else if (rights
|
||||
& ~(ChatRestriction::SendVoiceMessages
|
||||
| ChatRestriction::SendVideoMessages
|
||||
| ChatRestriction::SendPolls)) {
|
||||
return true;
|
||||
}
|
||||
for (const auto right : {
|
||||
ChatRestriction::SendVoiceMessages,
|
||||
ChatRestriction::SendVideoMessages,
|
||||
ChatRestriction::SendPolls,
|
||||
}) {
|
||||
if ((rights & right) && !user->amRestricted(right)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
if (!chat->amIn()) {
|
||||
return false;
|
||||
}
|
||||
for (const auto right : AllSendRestrictionsList()) {
|
||||
if ((rights & right) && !chat->amRestricted(right)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
using Flag = ChannelDataFlag;
|
||||
const auto allowed = channel->amIn()
|
||||
|| ((channel->flags() & Flag::HasLink)
|
||||
&& !(channel->flags() & Flag::JoinToWrite));
|
||||
if (!allowed || (forbidInForums && channel->isForum())) {
|
||||
return false;
|
||||
} else if (channel->canPublish()) {
|
||||
return true;
|
||||
} else if (channel->isBroadcast()) {
|
||||
return false;
|
||||
}
|
||||
for (const auto right : AllSendRestrictionsList()) {
|
||||
if ((rights & right) && !channel->amRestricted(right)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
Unexpected("Peer type in CanSendAnyOf.");
|
||||
}
|
||||
|
||||
std::optional<QString> RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction) {
|
||||
using Flag = ChatRestriction;
|
||||
if (const auto restricted = peer->amRestricted(restriction)) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
const auto result = (restriction == Flag::SendVoiceMessages)
|
||||
? tr::lng_restricted_send_voice_messages(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->name())
|
||||
: (restriction == Flag::SendVoiceMessages)
|
||||
? tr::lng_restricted_send_video_messages(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->name())
|
||||
: (restriction == Flag::SendPolls)
|
||||
? u"can't send polls :("_q
|
||||
: (restriction == Flag::PinMessages)
|
||||
? u"can't pin :("_q
|
||||
: std::optional<QString>();
|
||||
|
||||
Ensures(result.has_value());
|
||||
return result;
|
||||
}
|
||||
const auto all = restricted.isWithEveryone();
|
||||
const auto channel = peer->asChannel();
|
||||
if (!all && channel) {
|
||||
auto restrictedUntil = channel->restrictedUntil();
|
||||
if (restrictedUntil > 0
|
||||
&& !ChannelData::IsRestrictedForever(restrictedUntil)) {
|
||||
auto restrictedUntilDateTime = base::unixtime::parse(
|
||||
channel->restrictedUntil());
|
||||
auto date = QLocale().toString(
|
||||
restrictedUntilDateTime.date(),
|
||||
QLocale::ShortFormat);
|
||||
auto time = QLocale().toString(
|
||||
restrictedUntilDateTime.time(),
|
||||
QLocale::ShortFormat);
|
||||
|
||||
switch (restriction) {
|
||||
case Flag::SendPolls:
|
||||
return tr::lng_restricted_send_polls_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendOther:
|
||||
return tr::lng_restricted_send_message_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendPhotos:
|
||||
return tr::lng_restricted_send_photos_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendVideos:
|
||||
return tr::lng_restricted_send_videos_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendMusic:
|
||||
return tr::lng_restricted_send_music_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendFiles:
|
||||
return tr::lng_restricted_send_files_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendVideoMessages:
|
||||
return tr::lng_restricted_send_video_messages_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendVoiceMessages:
|
||||
return tr::lng_restricted_send_voice_messages_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendStickers:
|
||||
return tr::lng_restricted_send_stickers_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendGifs:
|
||||
return tr::lng_restricted_send_gifs_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendInline:
|
||||
case Flag::SendGames:
|
||||
return tr::lng_restricted_send_inline_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
}
|
||||
Unexpected("Restriction in Data::RestrictionErrorKey.");
|
||||
}
|
||||
}
|
||||
switch (restriction) {
|
||||
case Flag::SendPolls:
|
||||
return all
|
||||
? tr::lng_restricted_send_polls_all(tr::now)
|
||||
: tr::lng_restricted_send_polls(tr::now);
|
||||
case Flag::SendOther:
|
||||
return all
|
||||
? tr::lng_restricted_send_message_all(tr::now)
|
||||
: tr::lng_restricted_send_message(tr::now);
|
||||
case Flag::SendPhotos:
|
||||
return all
|
||||
? tr::lng_restricted_send_photos_all(tr::now)
|
||||
: tr::lng_restricted_send_photos(tr::now);
|
||||
case Flag::SendVideos:
|
||||
return all
|
||||
? tr::lng_restricted_send_videos_all(tr::now)
|
||||
: tr::lng_restricted_send_videos(tr::now);
|
||||
case Flag::SendMusic:
|
||||
return all
|
||||
? tr::lng_restricted_send_music_all(tr::now)
|
||||
: tr::lng_restricted_send_music(tr::now);
|
||||
case Flag::SendFiles:
|
||||
return all
|
||||
? tr::lng_restricted_send_files_all(tr::now)
|
||||
: tr::lng_restricted_send_files(tr::now);
|
||||
case Flag::SendVideoMessages:
|
||||
return all
|
||||
? tr::lng_restricted_send_video_messages_all(tr::now)
|
||||
: tr::lng_restricted_send_video_messages_group(tr::now);
|
||||
case Flag::SendVoiceMessages:
|
||||
return all
|
||||
? tr::lng_restricted_send_voice_messages_all(tr::now)
|
||||
: tr::lng_restricted_send_voice_messages_group(tr::now);
|
||||
case Flag::SendStickers:
|
||||
return all
|
||||
? tr::lng_restricted_send_stickers_all(tr::now)
|
||||
: tr::lng_restricted_send_stickers(tr::now);
|
||||
case Flag::SendGifs:
|
||||
return all
|
||||
? tr::lng_restricted_send_gifs_all(tr::now)
|
||||
: tr::lng_restricted_send_gifs(tr::now);
|
||||
case Flag::SendInline:
|
||||
case Flag::SendGames:
|
||||
return all
|
||||
? tr::lng_restricted_send_inline_all(tr::now)
|
||||
: tr::lng_restricted_send_inline(tr::now);
|
||||
}
|
||||
Unexpected("Restriction in Data::RestrictionErrorKey.");
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<QString> AnyFileRestrictionError(not_null<PeerData*> peer) {
|
||||
using Restriction = ChatRestriction;
|
||||
for (const auto right : FilesSendRestrictionsList()) {
|
||||
if (!RestrictionError(peer, right)) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return RestrictionError(peer, Restriction::SendFiles);
|
||||
}
|
||||
|
||||
std::optional<QString> FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) {
|
||||
const auto slowmode = peer->slowmodeApplied();
|
||||
if (slowmode) {
|
||||
if (!list.canBeSentInSlowmode()) {
|
||||
return tr::lng_slowmode_no_many(tr::now);
|
||||
} else if (list.files.size() > 1 && list.hasSticker()) {
|
||||
if (compress == false) {
|
||||
return tr::lng_slowmode_no_many(tr::now);
|
||||
} else {
|
||||
compress = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &file : list.files) {
|
||||
if (const auto error = FileRestrictionError(peer, file, compress)) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<QString> FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedFile &file,
|
||||
std::optional<bool> compress) {
|
||||
using Type = Ui::PreparedFile::Type;
|
||||
using Restriction = ChatRestriction;
|
||||
const auto stickers = RestrictionError(peer, Restriction::SendStickers);
|
||||
const auto gifs = RestrictionError(peer, Restriction::SendGifs);
|
||||
const auto photos = RestrictionError(peer, Restriction::SendPhotos);
|
||||
const auto videos = RestrictionError(peer, Restriction::SendVideos);
|
||||
const auto music = RestrictionError(peer, Restriction::SendMusic);
|
||||
const auto files = RestrictionError(peer, Restriction::SendFiles);
|
||||
if (!stickers && !gifs && !photos && !videos && !music && !files) {
|
||||
return {};
|
||||
}
|
||||
switch (file.type) {
|
||||
case Type::Photo:
|
||||
if (compress == true && photos) {
|
||||
return photos;
|
||||
} else if (const auto other = file.isSticker() ? stickers : files) {
|
||||
if ((compress == false || photos) && other) {
|
||||
return (file.isSticker() || !photos) ? other : photos;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::Video:
|
||||
if (const auto error = file.isGifv() ? gifs : videos) {
|
||||
return error;
|
||||
}
|
||||
break;
|
||||
case Type::Music:
|
||||
if (music) {
|
||||
return music;
|
||||
}
|
||||
break;
|
||||
case Type::File:
|
||||
if (files) {
|
||||
return files;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -7,10 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
enum class UserRestriction {
|
||||
SendVoiceMessages,
|
||||
SendVideoMessages,
|
||||
};
|
||||
namespace Ui {
|
||||
struct PreparedList;
|
||||
struct PreparedFile;
|
||||
} // namespace Ui
|
||||
|
||||
enum class ChatAdminRight {
|
||||
ChangeInfo = (1 << 0),
|
||||
|
@ -31,14 +31,22 @@ using ChatAdminRights = base::flags<ChatAdminRight>;
|
|||
|
||||
enum class ChatRestriction {
|
||||
ViewMessages = (1 << 0),
|
||||
SendMessages = (1 << 1),
|
||||
SendMedia = (1 << 2),
|
||||
|
||||
SendStickers = (1 << 3),
|
||||
SendGifs = (1 << 4),
|
||||
SendGames = (1 << 5),
|
||||
SendInline = (1 << 6),
|
||||
EmbedLinks = (1 << 7),
|
||||
SendPolls = (1 << 8),
|
||||
SendPhotos = (1 << 19),
|
||||
SendVideos = (1 << 20),
|
||||
SendVideoMessages = (1 << 21),
|
||||
SendMusic = (1 << 22),
|
||||
SendVoiceMessages = (1 << 23),
|
||||
SendFiles = (1 << 24),
|
||||
SendOther = (1 << 25),
|
||||
|
||||
EmbedLinks = (1 << 7),
|
||||
|
||||
ChangeInfo = (1 << 10),
|
||||
AddParticipants = (1 << 15),
|
||||
PinMessages = (1 << 17),
|
||||
|
@ -70,6 +78,8 @@ struct ChatRestrictionsInfo {
|
|||
|
||||
namespace Data {
|
||||
|
||||
class Thread;
|
||||
|
||||
struct AdminRightsSetOptions {
|
||||
bool isGroup : 1 = false;
|
||||
bool isForum : 1 = false;
|
||||
|
@ -83,4 +93,97 @@ struct RestrictionsSetOptions {
|
|||
[[nodiscard]] std::vector<ChatRestrictions> ListOfRestrictions(
|
||||
RestrictionsSetOptions options);
|
||||
|
||||
[[nodiscard]] inline constexpr auto AllSendRestrictionsList() {
|
||||
return std::array{
|
||||
ChatRestriction::SendOther,
|
||||
ChatRestriction::SendStickers,
|
||||
ChatRestriction::SendGifs,
|
||||
ChatRestriction::SendGames,
|
||||
ChatRestriction::SendInline,
|
||||
ChatRestriction::SendPolls,
|
||||
ChatRestriction::SendPhotos,
|
||||
ChatRestriction::SendVideos,
|
||||
ChatRestriction::SendVideoMessages,
|
||||
ChatRestriction::SendMusic,
|
||||
ChatRestriction::SendVoiceMessages,
|
||||
ChatRestriction::SendFiles,
|
||||
};
|
||||
}
|
||||
[[nodiscard]] inline constexpr auto FilesSendRestrictionsList() {
|
||||
return std::array{
|
||||
ChatRestriction::SendStickers,
|
||||
ChatRestriction::SendGifs,
|
||||
ChatRestriction::SendPhotos,
|
||||
ChatRestriction::SendVideos,
|
||||
ChatRestriction::SendMusic,
|
||||
ChatRestriction::SendFiles,
|
||||
};
|
||||
}
|
||||
[[nodiscard]] inline constexpr auto TabbedPanelSendRestrictionsList() {
|
||||
return std::array{
|
||||
ChatRestriction::SendStickers,
|
||||
ChatRestriction::SendGifs,
|
||||
ChatRestriction::SendOther,
|
||||
};
|
||||
}
|
||||
[[nodiscard]] ChatRestrictions AllSendRestrictions();
|
||||
[[nodiscard]] ChatRestrictions FilesSendRestrictions();
|
||||
[[nodiscard]] ChatRestrictions TabbedPanelSendRestrictions();
|
||||
|
||||
[[nodiscard]] bool CanSendAnyOf(
|
||||
not_null<Thread*> thread,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums = true);
|
||||
[[nodiscard]] bool CanSendAnyOf(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums = true);
|
||||
|
||||
[[nodiscard]] inline bool CanSend(
|
||||
not_null<Thread*> thread,
|
||||
ChatRestriction right,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOf(thread, right, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline bool CanSend(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction right,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOf(peer, right, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline bool CanSendTexts(
|
||||
not_null<Thread*> thread,
|
||||
bool forbidInForums = true) {
|
||||
return CanSend(thread, ChatRestriction::SendOther, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline bool CanSendTexts(
|
||||
not_null<PeerData*> peer,
|
||||
bool forbidInForums = true) {
|
||||
return CanSend(peer, ChatRestriction::SendOther, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline bool CanSendAnything(
|
||||
not_null<Thread*> thread,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOf(thread, AllSendRestrictions(), forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline bool CanSendAnything(
|
||||
not_null<PeerData*> peer,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOf(peer, AllSendRestrictions(), forbidInForums);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<QString> RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction);
|
||||
[[nodiscard]] std::optional<QString> AnyFileRestrictionError(
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] std::optional<QString> FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress);
|
||||
[[nodiscard]] std::optional<QString> FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedFile &file,
|
||||
std::optional<bool> compress);
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -841,6 +841,22 @@ void DocumentData::setLoadedInMediaCache(bool loaded) {
|
|||
}
|
||||
}
|
||||
|
||||
ChatRestriction DocumentData::requiredSendRight() const {
|
||||
return isVideoFile()
|
||||
? ChatRestriction::SendVideos
|
||||
: isSong()
|
||||
? ChatRestriction::SendMusic
|
||||
: isVoiceMessage()
|
||||
? ChatRestriction::SendVoiceMessages
|
||||
: isVideoMessage()
|
||||
? ChatRestriction::SendVideoMessages
|
||||
: sticker()
|
||||
? ChatRestriction::SendStickers
|
||||
: isAnimation()
|
||||
? ChatRestriction::SendGifs
|
||||
: ChatRestriction::SendFiles;
|
||||
}
|
||||
|
||||
void DocumentData::setFileName(const QString &remoteFileName) {
|
||||
_filename = remoteFileName;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/file_location.h"
|
||||
#include "ui/image/image.h"
|
||||
|
||||
enum class ChatRestriction;
|
||||
class mtpFileLoader;
|
||||
|
||||
namespace Images {
|
||||
|
@ -126,6 +127,8 @@ public:
|
|||
[[nodiscard]] bool loadedInMediaCache() const;
|
||||
void setLoadedInMediaCache(bool loaded);
|
||||
|
||||
[[nodiscard]] ChatRestriction requiredSendRight() const;
|
||||
|
||||
void setWaitingForAlbum();
|
||||
[[nodiscard]] bool waitingForAlbum() const;
|
||||
|
||||
|
|
|
@ -249,18 +249,6 @@ bool ForumTopic::my() const {
|
|||
return (_flags & Flag::My);
|
||||
}
|
||||
|
||||
bool ForumTopic::canWrite() const {
|
||||
const auto channel = this->channel();
|
||||
return channel->amIn()
|
||||
&& !channel->amRestricted(ChatRestriction::SendMessages)
|
||||
&& (!closed() || canToggleClosed());
|
||||
}
|
||||
|
||||
bool ForumTopic::canSendPolls() const {
|
||||
return canWrite()
|
||||
&& !channel()->amRestricted(ChatRestriction::SendPolls);
|
||||
}
|
||||
|
||||
bool ForumTopic::canEdit() const {
|
||||
return my() || channel()->canManageTopics();
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/flags.h"
|
||||
|
||||
class ChannelData;
|
||||
enum class ChatRestriction;
|
||||
|
||||
namespace style {
|
||||
struct ForumTopicIcon;
|
||||
|
@ -80,8 +81,6 @@ public:
|
|||
[[nodiscard]] not_null<HistoryView::ListMemento*> listMemento();
|
||||
|
||||
[[nodiscard]] bool my() const;
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
[[nodiscard]] bool canSendPolls() const;
|
||||
[[nodiscard]] bool canEdit() const;
|
||||
[[nodiscard]] bool canToggleClosed() const;
|
||||
[[nodiscard]] bool canTogglePinned() const;
|
||||
|
|
|
@ -460,10 +460,6 @@ bool Media::forceForwardedInfo() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
QString Media::errorTextForForward(not_null<PeerData*> peer) const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool Media::hasSpoiler() const {
|
||||
return false;
|
||||
}
|
||||
|
@ -686,13 +682,6 @@ bool MediaPhoto::allowsEditMedia() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
QString MediaPhoto::errorTextForForward(not_null<PeerData*> peer) const {
|
||||
return Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendMedia
|
||||
).value_or(QString());
|
||||
}
|
||||
|
||||
bool MediaPhoto::hasSpoiler() const {
|
||||
return _spoiler;
|
||||
}
|
||||
|
@ -1040,46 +1029,6 @@ bool MediaFile::dropForwardedInfo() const {
|
|||
return _document->isSong();
|
||||
}
|
||||
|
||||
QString MediaFile::errorTextForForward(not_null<PeerData*> peer) const {
|
||||
if (const auto sticker = _document->sticker()) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendStickers)) {
|
||||
return *error;
|
||||
}
|
||||
} else if (_document->isAnimation()) {
|
||||
if (_document->isVideoMessage()) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
return *error;
|
||||
}
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
UserRestriction::SendVideoMessages)) {
|
||||
return *error;
|
||||
}
|
||||
} else {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendGifs)) {
|
||||
return *error;
|
||||
}
|
||||
}
|
||||
} else if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
return *error;
|
||||
} else if (_document->isVoiceMessage()) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
UserRestriction::SendVoiceMessages)) {
|
||||
return *error;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool MediaFile::hasSpoiler() const {
|
||||
return _spoiler;
|
||||
}
|
||||
|
@ -1589,13 +1538,6 @@ TextForMimeData MediaGame::clipboardText() const {
|
|||
return TextForMimeData();
|
||||
}
|
||||
|
||||
QString MediaGame::errorTextForForward(not_null<PeerData*> peer) const {
|
||||
return Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendGames
|
||||
).value_or(QString());
|
||||
}
|
||||
|
||||
bool MediaGame::dropForwardedInfo() const {
|
||||
return true;
|
||||
}
|
||||
|
@ -1773,16 +1715,6 @@ TextForMimeData MediaPoll::clipboardText() const {
|
|||
return TextForMimeData::Simple(text);
|
||||
}
|
||||
|
||||
QString MediaPoll::errorTextForForward(not_null<PeerData*> peer) const {
|
||||
if (_poll->publicVotes() && peer->isChannel() && !peer->isMegagroup()) {
|
||||
return tr::lng_restricted_send_public_polls(tr::now);
|
||||
}
|
||||
return Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendPolls
|
||||
).value_or(QString());
|
||||
}
|
||||
|
||||
bool MediaPoll::updateInlineResultMedia(const MTPMessageMedia &media) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1888,7 +1820,7 @@ ClickHandlerPtr MediaDice::MakeHandler(
|
|||
.durationMs = Ui::Toast::kDefaultDuration * 2,
|
||||
.multiline = true,
|
||||
};
|
||||
if (history->peer->canWrite()) {
|
||||
if (Data::CanSend(history->peer, ChatRestriction::SendOther)) {
|
||||
auto link = Ui::Text::Link(
|
||||
tr::lng_about_random_send(tr::now).toUpper());
|
||||
link.entities.push_back(
|
||||
|
|
|
@ -128,7 +128,6 @@ public:
|
|||
virtual bool forwardedBecomesUnread() const;
|
||||
virtual bool dropForwardedInfo() const;
|
||||
virtual bool forceForwardedInfo() const;
|
||||
virtual QString errorTextForForward(not_null<PeerData*> peer) const;
|
||||
[[nodiscard]] virtual bool hasSpoiler() const;
|
||||
|
||||
[[nodiscard]] virtual bool consumeMessageText(
|
||||
|
@ -190,7 +189,6 @@ public:
|
|||
TextForMimeData clipboardText() const override;
|
||||
bool allowsEditCaption() const override;
|
||||
bool allowsEditMedia() const override;
|
||||
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
||||
bool hasSpoiler() const override;
|
||||
|
||||
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||
|
@ -234,7 +232,6 @@ public:
|
|||
bool allowsEditMedia() const override;
|
||||
bool forwardedBecomesUnread() const override;
|
||||
bool dropForwardedInfo() const override;
|
||||
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
||||
bool hasSpoiler() const override;
|
||||
|
||||
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||
|
@ -395,7 +392,6 @@ public:
|
|||
TextWithEntities notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextForMimeData clipboardText() const override;
|
||||
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
||||
bool dropForwardedInfo() const override;
|
||||
|
||||
bool consumeMessageText(const TextWithEntities &text) override;
|
||||
|
@ -460,7 +456,6 @@ public:
|
|||
TextWithEntities notificationText() const override;
|
||||
QString pinnedTextSubstring() const override;
|
||||
TextForMimeData clipboardText() const override;
|
||||
QString errorTextForForward(not_null<PeerData*> peer) const override;
|
||||
|
||||
bool updateInlineResultMedia(const MTPMessageMedia &media) override;
|
||||
bool updateSentMedia(const MTPMessageMedia &media) override;
|
||||
|
|
|
@ -462,7 +462,7 @@ QString PeerData::computeUnavailableReason() const {
|
|||
// This is duplicated in CanPinMessagesValue().
|
||||
bool PeerData::canPinMessages() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->flags() & UserDataFlag::CanPinMessages;
|
||||
return !user->amRestricted(ChatRestriction::PinMessages);
|
||||
} else if (const auto chat = asChat()) {
|
||||
return chat->amIn()
|
||||
&& !chat->amRestricted(ChatRestriction::PinMessages);
|
||||
|
@ -881,18 +881,6 @@ Data::ForumTopic *PeerData::forumTopicFor(MsgId rootId) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool PeerData::canWrite(bool checkForForum) const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->canWrite();
|
||||
} else if (const auto channel = asChannel()) {
|
||||
return channel->canWrite(checkForForum);
|
||||
} else if (const auto chat = asChat()) {
|
||||
return chat->canWrite();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeerData::allowsForwarding() const {
|
||||
if (const auto user = asUser()) {
|
||||
return true;
|
||||
|
@ -920,10 +908,26 @@ Data::RestrictionCheckResult PeerData::amRestricted(
|
|||
return chat->hasAdminRights();
|
||||
}
|
||||
};
|
||||
if (const auto channel = asChannel()) {
|
||||
if (const auto user = asUser()) {
|
||||
return (right == ChatRestriction::SendVoiceMessages
|
||||
|| right == ChatRestriction::SendVideoMessages)
|
||||
? ((user->flags() & UserDataFlag::VoiceMessagesForbidden)
|
||||
? Result::Explicit()
|
||||
: Result::Allowed())
|
||||
: (right == ChatRestriction::SendPolls)
|
||||
? ((!user->isBot() || user->isSupport())
|
||||
? Result::Explicit()
|
||||
: Result::Allowed())
|
||||
: (right == ChatRestriction::PinMessages)
|
||||
? ((user->flags() & UserDataFlag::CanPinMessages)
|
||||
? Result::Allowed()
|
||||
: Result::Explicit())
|
||||
: Result::Allowed();
|
||||
} else if (const auto channel = asChannel()) {
|
||||
const auto defaultRestrictions = channel->defaultRestrictions()
|
||||
| (channel->isPublic()
|
||||
? (ChatRestriction::PinMessages | ChatRestriction::ChangeInfo)
|
||||
? (ChatRestriction::PinMessages
|
||||
| ChatRestriction::ChangeInfo)
|
||||
: ChatRestrictions(0));
|
||||
return (channel->amCreator() || allowByAdminRights(right, channel))
|
||||
? Result::Allowed()
|
||||
|
@ -1010,19 +1014,6 @@ int PeerData::slowmodeSecondsLeft() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool PeerData::canSendPolls() const {
|
||||
if (const auto user = asUser()) {
|
||||
return user->isBot()
|
||||
&& !user->isRepliesChat()
|
||||
&& !user->isSupport();
|
||||
} else if (const auto chat = asChat()) {
|
||||
return chat->canSendPolls();
|
||||
} else if (const auto channel = asChannel()) {
|
||||
return channel->canSendPolls();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeerData::canManageGroupCall() const {
|
||||
if (const auto chat = asChat()) {
|
||||
return chat->amCreator()
|
||||
|
@ -1109,95 +1100,6 @@ void PeerData::setMessagesTTL(TimeId period) {
|
|||
|
||||
namespace Data {
|
||||
|
||||
std::optional<QString> RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction) {
|
||||
using Flag = ChatRestriction;
|
||||
if (const auto restricted = peer->amRestricted(restriction)) {
|
||||
const auto all = restricted.isWithEveryone();
|
||||
const auto channel = peer->asChannel();
|
||||
if (!all && channel) {
|
||||
auto restrictedUntil = channel->restrictedUntil();
|
||||
if (restrictedUntil > 0 && !ChannelData::IsRestrictedForever(restrictedUntil)) {
|
||||
auto restrictedUntilDateTime = base::unixtime::parse(channel->restrictedUntil());
|
||||
auto date = QLocale().toString(restrictedUntilDateTime.date(), QLocale::ShortFormat);
|
||||
auto time = QLocale().toString(restrictedUntilDateTime.time(), QLocale::ShortFormat);
|
||||
|
||||
switch (restriction) {
|
||||
case Flag::SendPolls:
|
||||
return tr::lng_restricted_send_polls_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendMessages:
|
||||
return tr::lng_restricted_send_message_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendMedia:
|
||||
return tr::lng_restricted_send_media_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendStickers:
|
||||
return tr::lng_restricted_send_stickers_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendGifs:
|
||||
return tr::lng_restricted_send_gifs_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
case Flag::SendInline:
|
||||
case Flag::SendGames:
|
||||
return tr::lng_restricted_send_inline_until(
|
||||
tr::now, lt_date, date, lt_time, time);
|
||||
}
|
||||
Unexpected("Restriction in Data::RestrictionErrorKey.");
|
||||
}
|
||||
}
|
||||
switch (restriction) {
|
||||
case Flag::SendPolls:
|
||||
return all
|
||||
? tr::lng_restricted_send_polls_all(tr::now)
|
||||
: tr::lng_restricted_send_polls(tr::now);
|
||||
case Flag::SendMessages:
|
||||
return all
|
||||
? tr::lng_restricted_send_message_all(tr::now)
|
||||
: tr::lng_restricted_send_message(tr::now);
|
||||
case Flag::SendMedia:
|
||||
return all
|
||||
? tr::lng_restricted_send_media_all(tr::now)
|
||||
: tr::lng_restricted_send_media(tr::now);
|
||||
case Flag::SendStickers:
|
||||
return all
|
||||
? tr::lng_restricted_send_stickers_all(tr::now)
|
||||
: tr::lng_restricted_send_stickers(tr::now);
|
||||
case Flag::SendGifs:
|
||||
return all
|
||||
? tr::lng_restricted_send_gifs_all(tr::now)
|
||||
: tr::lng_restricted_send_gifs(tr::now);
|
||||
case Flag::SendInline:
|
||||
case Flag::SendGames:
|
||||
return all
|
||||
? tr::lng_restricted_send_inline_all(tr::now)
|
||||
: tr::lng_restricted_send_inline(tr::now);
|
||||
}
|
||||
Unexpected("Restriction in Data::RestrictionErrorKey.");
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<QString> RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
UserRestriction restriction) {
|
||||
const auto user = peer->asUser();
|
||||
if (user && !user->canReceiveVoices()) {
|
||||
const auto voice = restriction == UserRestriction::SendVoiceMessages;
|
||||
if (voice
|
||||
|| (restriction == UserRestriction::SendVideoMessages)) {
|
||||
return (voice
|
||||
? tr::lng_restricted_send_voice_messages
|
||||
: tr::lng_restricted_send_video_messages)(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->name());
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void SetTopPinnedMessageId(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId messageId) {
|
||||
|
|
|
@ -20,7 +20,6 @@ class ChatData;
|
|||
class ChannelData;
|
||||
|
||||
enum class ChatRestriction;
|
||||
enum class UserRestriction;
|
||||
|
||||
namespace Ui {
|
||||
class EmptyUserpic;
|
||||
|
@ -205,7 +204,6 @@ public:
|
|||
return _notify;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool canWrite(bool checkForForum = true) const;
|
||||
[[nodiscard]] bool allowsForwarding() const;
|
||||
[[nodiscard]] Data::RestrictionCheckResult amRestricted(
|
||||
ChatRestriction right) const;
|
||||
|
@ -214,7 +212,6 @@ public:
|
|||
[[nodiscard]] bool slowmodeApplied() const;
|
||||
[[nodiscard]] rpl::producer<bool> slowmodeAppliedValue() const;
|
||||
[[nodiscard]] int slowmodeSecondsLeft() const;
|
||||
[[nodiscard]] bool canSendPolls() const;
|
||||
[[nodiscard]] bool canManageGroupCall() const;
|
||||
|
||||
[[nodiscard]] UserData *asUser();
|
||||
|
@ -454,14 +451,6 @@ private:
|
|||
|
||||
namespace Data {
|
||||
|
||||
std::optional<QString> RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction);
|
||||
|
||||
std::optional<QString> RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
UserRestriction restriction);
|
||||
|
||||
void SetTopPinnedMessageId(
|
||||
not_null<PeerData*> peer,
|
||||
MsgId messageId);
|
||||
|
|
|
@ -164,129 +164,136 @@ inline auto DefaultRestrictionValue(
|
|||
return SingleFlagValue(DefaultRestrictionsValue(chat), flag);
|
||||
}
|
||||
|
||||
rpl::producer<bool> CanWriteValue(UserData *user) {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
if (user->isRepliesChat()) {
|
||||
return rpl::single(false);
|
||||
// Duplicated in CanSendAnyOf().
|
||||
[[nodiscard]] rpl::producer<bool> CanSendAnyOfValue(
|
||||
not_null<Thread*> thread,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums) {
|
||||
if (const auto topic = thread->asTopic()) {
|
||||
using Flag = ChannelDataFlag;
|
||||
const auto mask = Flag()
|
||||
| Flag::Left
|
||||
| Flag::JoinToWrite
|
||||
| Flag::HasLink
|
||||
| Flag::Forbidden
|
||||
| Flag::Creator;
|
||||
const auto channel = topic->channel();
|
||||
return rpl::combine(
|
||||
PeerFlagsValue(channel.get(), mask),
|
||||
RestrictionsValue(channel, rights),
|
||||
DefaultRestrictionsValue(channel, rights),
|
||||
AdminRightsValue(channel, ChatAdminRight::ManageTopics),
|
||||
topic->session().changes().topicFlagsValue(
|
||||
topic,
|
||||
TopicUpdate::Flag::Closed),
|
||||
[=](
|
||||
ChannelDataFlags flags,
|
||||
ChatRestrictions sendRestriction,
|
||||
ChatRestrictions defaultSendRestriction,
|
||||
auto,
|
||||
auto) {
|
||||
const auto notAmInFlags = Flag::Left | Flag::Forbidden;
|
||||
const auto allowed = !(flags & notAmInFlags)
|
||||
|| ((flags & Flag::HasLink)
|
||||
&& !(flags & Flag::JoinToWrite));
|
||||
return allowed
|
||||
&& ((flags & Flag::Creator)
|
||||
|| (!sendRestriction && !defaultSendRestriction))
|
||||
&& (!topic->closed() || topic->canToggleClosed());
|
||||
});
|
||||
}
|
||||
return PeerFlagValue(user, UserDataFlag::Deleted)
|
||||
| rpl::map(!_1);
|
||||
return CanSendAnyOfValue(thread->peer(), rights, forbidInForums);
|
||||
}
|
||||
|
||||
rpl::producer<bool> CanWriteValue(ChatData *chat) {
|
||||
using namespace rpl::mappers;
|
||||
const auto mask = 0
|
||||
| ChatDataFlag::Deactivated
|
||||
| ChatDataFlag::Forbidden
|
||||
| ChatDataFlag::Left
|
||||
| ChatDataFlag::Creator;
|
||||
return rpl::combine(
|
||||
PeerFlagsValue(chat, mask),
|
||||
AdminRightsValue(chat),
|
||||
DefaultRestrictionValue(
|
||||
chat,
|
||||
ChatRestriction::SendMessages),
|
||||
[](
|
||||
// Duplicated in CanSendAnyOf().
|
||||
[[nodiscard]] rpl::producer<bool> CanSendAnyOfValue(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
if (user->isRepliesChat()) {
|
||||
return rpl::single(false);
|
||||
}
|
||||
using namespace rpl::mappers;
|
||||
const auto other = rights & ~(ChatRestriction::SendPolls
|
||||
| ChatRestriction::SendVoiceMessages
|
||||
| ChatRestriction::SendVideoMessages);
|
||||
if (other) {
|
||||
return PeerFlagValue(user, UserDataFlag::Deleted)
|
||||
| rpl::map(!_1);
|
||||
} else if (rights & ChatRestriction::SendPolls) {
|
||||
if (CanSend(user, ChatRestriction::SendPolls)) {
|
||||
return PeerFlagValue(user, UserDataFlag::Deleted)
|
||||
| rpl::map(!_1);
|
||||
} else if (rights == ChatRestriction::SendPolls) {
|
||||
return rpl::single(false);
|
||||
}
|
||||
}
|
||||
const auto mask = UserDataFlag::Deleted
|
||||
| UserDataFlag::VoiceMessagesForbidden;
|
||||
return PeerFlagsValue(user, mask) | rpl::map(!_1);
|
||||
} else if (const auto chat = peer->asChat()) {
|
||||
const auto mask = ChatDataFlag()
|
||||
| ChatDataFlag::Deactivated
|
||||
| ChatDataFlag::Forbidden
|
||||
| ChatDataFlag::Left
|
||||
| ChatDataFlag::Creator;
|
||||
return rpl::combine(
|
||||
PeerFlagsValue(chat, mask),
|
||||
AdminRightsValue(chat),
|
||||
DefaultRestrictionsValue(chat, rights),
|
||||
[rights](
|
||||
ChatDataFlags flags,
|
||||
Data::Flags<ChatAdminRights>::Change adminRights,
|
||||
bool defaultSendMessagesRestriction) {
|
||||
const auto amOutFlags = 0
|
||||
ChatRestrictions defaultSendRestrictions) {
|
||||
const auto amOutFlags = ChatDataFlag()
|
||||
| ChatDataFlag::Deactivated
|
||||
| ChatDataFlag::Forbidden
|
||||
| ChatDataFlag::Left;
|
||||
return !(flags & amOutFlags)
|
||||
&& ((flags & ChatDataFlag::Creator)
|
||||
|| (adminRights.value != ChatAdminRights(0))
|
||||
|| !defaultSendMessagesRestriction);
|
||||
return !(flags & amOutFlags)
|
||||
&& ((flags & ChatDataFlag::Creator)
|
||||
|| (adminRights.value != ChatAdminRights(0))
|
||||
|| (rights & ~defaultSendRestrictions));
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<bool> CanWriteValue(ChannelData *channel, bool checkForForum) {
|
||||
using Flag = ChannelDataFlag;
|
||||
const auto mask = 0
|
||||
| Flag::Left
|
||||
| Flag::Forum
|
||||
| Flag::JoinToWrite
|
||||
| Flag::HasLink
|
||||
| Flag::Forbidden
|
||||
| Flag::Creator
|
||||
| Flag::Broadcast;
|
||||
return rpl::combine(
|
||||
PeerFlagsValue(channel, mask),
|
||||
AdminRightValue(
|
||||
channel,
|
||||
ChatAdminRight::PostMessages),
|
||||
RestrictionValue(
|
||||
channel,
|
||||
ChatRestriction::SendMessages),
|
||||
DefaultRestrictionValue(
|
||||
channel,
|
||||
ChatRestriction::SendMessages),
|
||||
[=](
|
||||
ChannelDataFlags flags,
|
||||
bool postMessagesRight,
|
||||
bool sendMessagesRestriction,
|
||||
bool defaultSendMessagesRestriction) {
|
||||
const auto notAmInFlags = Flag::Left | Flag::Forbidden;
|
||||
const auto forumRestriction = checkForForum
|
||||
&& (flags & Flag::Forum);
|
||||
const auto allowed = !(flags & notAmInFlags)
|
||||
|| ((flags & Flag::HasLink) && !(flags & Flag::JoinToWrite));
|
||||
return allowed
|
||||
&& !forumRestriction
|
||||
&& (postMessagesRight
|
||||
|| (flags & Flag::Creator)
|
||||
|| (!(flags & Flag::Broadcast)
|
||||
&& !sendMessagesRestriction
|
||||
&& !defaultSendMessagesRestriction));
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<bool> CanWriteValue(
|
||||
not_null<PeerData*> peer,
|
||||
bool checkForForum) {
|
||||
if (auto user = peer->asUser()) {
|
||||
return CanWriteValue(user);
|
||||
} else if (auto chat = peer->asChat()) {
|
||||
return CanWriteValue(chat);
|
||||
} else if (auto channel = peer->asChannel()) {
|
||||
return CanWriteValue(channel, checkForForum);
|
||||
} else if (const auto channel = peer->asChannel()) {
|
||||
using Flag = ChannelDataFlag;
|
||||
const auto mask = Flag()
|
||||
| Flag::Left
|
||||
| Flag::Forum
|
||||
| Flag::JoinToWrite
|
||||
| Flag::HasLink
|
||||
| Flag::Forbidden
|
||||
| Flag::Creator
|
||||
| Flag::Broadcast;
|
||||
return rpl::combine(
|
||||
PeerFlagsValue(channel, mask),
|
||||
AdminRightValue(
|
||||
channel,
|
||||
ChatAdminRight::PostMessages),
|
||||
RestrictionsValue(channel, rights),
|
||||
DefaultRestrictionsValue(channel, rights),
|
||||
[=](
|
||||
ChannelDataFlags flags,
|
||||
bool postMessagesRight,
|
||||
ChatRestrictions sendRestriction,
|
||||
ChatRestrictions defaultSendRestriction) {
|
||||
const auto notAmInFlags = Flag::Left | Flag::Forbidden;
|
||||
const auto forumRestriction = forbidInForums
|
||||
&& (flags & Flag::Forum);
|
||||
const auto allowed = !(flags & notAmInFlags)
|
||||
|| ((flags & Flag::HasLink)
|
||||
&& !(flags & Flag::JoinToWrite));
|
||||
const auto restricted = sendRestriction
|
||||
| defaultSendRestriction;
|
||||
return allowed
|
||||
&& !forumRestriction
|
||||
&& (postMessagesRight
|
||||
|| (flags & Flag::Creator)
|
||||
|| (!(flags & Flag::Broadcast)
|
||||
&& (rights & ~restricted)));
|
||||
});
|
||||
}
|
||||
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());
|
||||
});
|
||||
Unexpected("Peer type in Data::CanSendAnyOfValue.");
|
||||
}
|
||||
|
||||
// This is duplicated in PeerData::canPinMessages().
|
||||
|
|
|
@ -7,10 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include <rpl/filter.h>
|
||||
#include <rpl/map.h>
|
||||
#include <rpl/combine.h>
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_chat_participant_status.h"
|
||||
|
||||
enum class ImageRoundRadius;
|
||||
|
||||
|
@ -53,6 +51,7 @@ template <
|
|||
typename ChangeType = typename PeerType::Flags::Change>
|
||||
inline auto PeerFlagsValue(PeerType *peer) {
|
||||
Expects(peer != nullptr);
|
||||
|
||||
return peer->flagsValue();
|
||||
}
|
||||
|
||||
|
@ -101,15 +100,48 @@ inline auto PeerFullFlagValue(
|
|||
return SingleFlagValue(PeerFullFlagsValue(peer), flag);
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(UserData *user);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(ChatData *chat);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(
|
||||
ChannelData *channel,
|
||||
bool checkForForum = true);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(
|
||||
[[nodiscard]] rpl::producer<bool> CanSendAnyOfValue(
|
||||
not_null<Data::Thread*> thread,
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums = true);
|
||||
[[nodiscard]] rpl::producer<bool> CanSendAnyOfValue(
|
||||
not_null<PeerData*> peer,
|
||||
bool checkForForum = true);
|
||||
[[nodiscard]] rpl::producer<bool> CanWriteValue(not_null<ForumTopic*> topic);
|
||||
ChatRestrictions rights,
|
||||
bool forbidInForums = true);
|
||||
|
||||
[[nodiscard]] inline rpl::producer<bool> CanSendValue(
|
||||
not_null<Thread*> thread,
|
||||
ChatRestriction right,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOfValue(thread, right, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline rpl::producer<bool> CanSendValue(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction right,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOfValue(peer, right, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline rpl::producer<bool> CanSendTextsValue(
|
||||
not_null<Thread*> thread,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendValue(thread, ChatRestriction::SendOther, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline rpl::producer<bool> CanSendTextsValue(
|
||||
not_null<PeerData*> peer,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendValue(peer, ChatRestriction::SendOther, forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline rpl::producer<bool> CanSendAnythingValue(
|
||||
not_null<Thread*> thread,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOfValue(thread, AllSendRestrictions(), forbidInForums);
|
||||
}
|
||||
[[nodiscard]] inline rpl::producer<bool> CanSendAnythingValue(
|
||||
not_null<PeerData*> peer,
|
||||
bool forbidInForums = true) {
|
||||
return CanSendAnyOfValue(peer, AllSendRestrictions(), forbidInForums);
|
||||
}
|
||||
|
||||
[[nodiscard]] rpl::producer<bool> CanPinMessagesValue(
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<bool> CanManageGroupCallValue(
|
||||
|
|
|
@ -392,7 +392,7 @@ Data::MessagesSlice ScheduledMessages::list(not_null<History*> history) {
|
|||
|
||||
void ScheduledMessages::request(not_null<History*> history) {
|
||||
const auto peer = history->peer;
|
||||
if (peer->isBroadcast() && !peer->canWrite()) {
|
||||
if (peer->isBroadcast() && !Data::CanSendAnything(peer)) {
|
||||
return;
|
||||
}
|
||||
auto &request = _requests[history];
|
||||
|
|
|
@ -44,11 +44,6 @@ const PeerNotifySettings &Thread::notify() const {
|
|||
return const_cast<Thread*>(this)->notify();
|
||||
}
|
||||
|
||||
bool Thread::canWrite() const {
|
||||
const auto topic = asTopic();
|
||||
return topic ? topic->canWrite() : peer()->canWrite();
|
||||
}
|
||||
|
||||
void Thread::setUnreadThingsKnown() {
|
||||
_flags |= Flag::UnreadThingsKnown;
|
||||
}
|
||||
|
|
|
@ -7,12 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/flags.h"
|
||||
#include "dialogs/dialogs_entry.h"
|
||||
#include "dialogs/ui/dialogs_message_view.h"
|
||||
#include "ui/text/text.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
enum class ChatRestriction;
|
||||
using ChatRestrictions = base::flags<ChatRestriction>;
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
@ -67,7 +71,6 @@ public:
|
|||
[[nodiscard]] PeerNotifySettings ¬ify();
|
||||
[[nodiscard]] const PeerNotifySettings ¬ify() const;
|
||||
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
void setUnreadThingsKnown();
|
||||
[[nodiscard]] HistoryUnreadThings::Proxy unreadMentions();
|
||||
[[nodiscard]] HistoryUnreadThings::ConstProxy unreadMentions() const;
|
||||
|
|
|
@ -293,11 +293,6 @@ bool UserData::isInaccessible() const {
|
|||
return flags() & UserDataFlag::Deleted;
|
||||
}
|
||||
|
||||
bool UserData::canWrite() const {
|
||||
// Duplicated in Data::CanWriteValue().
|
||||
return !isInaccessible() && !isRepliesChat();
|
||||
}
|
||||
|
||||
bool UserData::applyMinPhoto() const {
|
||||
return !(flags() & UserDataFlag::DiscardMinPhoto);
|
||||
}
|
||||
|
@ -314,10 +309,6 @@ bool UserData::canReceiveGifts() const {
|
|||
return flags() & UserDataFlag::CanReceiveGifts;
|
||||
}
|
||||
|
||||
bool UserData::canReceiveVoices() const {
|
||||
return !(flags() & UserDataFlag::VoiceMessagesForbidden);
|
||||
}
|
||||
|
||||
bool UserData::canShareThisContactFast() const {
|
||||
return !_phone.isEmpty();
|
||||
}
|
||||
|
|
|
@ -112,7 +112,6 @@ public:
|
|||
[[nodiscard]] bool isBot() const;
|
||||
[[nodiscard]] bool isSupport() const;
|
||||
[[nodiscard]] bool isInaccessible() const;
|
||||
[[nodiscard]] bool canWrite() const;
|
||||
[[nodiscard]] bool applyMinPhoto() const;
|
||||
[[nodiscard]] bool hasPersonalPhoto() const;
|
||||
|
||||
|
@ -120,7 +119,6 @@ public:
|
|||
[[nodiscard]] bool canAddContact() const;
|
||||
|
||||
[[nodiscard]] bool canReceiveGifts() const;
|
||||
[[nodiscard]] bool canReceiveVoices() const;
|
||||
|
||||
// In Data::Session::processUsers() we check only that.
|
||||
// When actually trying to share contact we perform
|
||||
|
|
|
@ -255,8 +255,17 @@ QString GeneratePermissionsChangeText(
|
|||
|
||||
static auto phraseMap = std::map<Flags, tr::phrase<>>{
|
||||
{ Flag::ViewMessages, tr::lng_admin_log_banned_view_messages },
|
||||
{ Flag::SendMessages, tr::lng_admin_log_banned_send_messages },
|
||||
{ Flag::SendMedia, tr::lng_admin_log_banned_send_media },
|
||||
{ Flag::SendOther, tr::lng_admin_log_banned_send_messages },
|
||||
{ Flag::SendPhotos, tr::lng_admin_log_banned_send_photos },
|
||||
{ Flag::SendVideos, tr::lng_admin_log_banned_send_videos },
|
||||
{ Flag::SendMusic, tr::lng_admin_log_banned_send_music },
|
||||
{ Flag::SendFiles, tr::lng_admin_log_banned_send_files },
|
||||
{
|
||||
Flag::SendVoiceMessages,
|
||||
tr::lng_admin_log_banned_send_voice_messages },
|
||||
{
|
||||
Flag::SendVideoMessages,
|
||||
tr::lng_admin_log_banned_send_video_messages },
|
||||
{ Flag::SendStickers
|
||||
| Flag::SendGifs
|
||||
| Flag::SendInline
|
||||
|
|
|
@ -947,13 +947,13 @@ not_null<HistoryItem*> History::addNewToBack(
|
|||
if (peer->isChat()) {
|
||||
botNotInChat = item->from()->isUser()
|
||||
&& (!peer->asChat()->participants.empty()
|
||||
|| !peer->canWrite())
|
||||
|| !Data::CanSendAnything(peer))
|
||||
&& !peer->asChat()->participants.contains(
|
||||
item->from()->asUser());
|
||||
} else if (peer->isMegagroup()) {
|
||||
botNotInChat = item->from()->isUser()
|
||||
&& (peer->asChannel()->mgInfo->botStatus != 0
|
||||
|| !peer->canWrite())
|
||||
|| !Data::CanSendAnything(peer))
|
||||
&& !peer->asChannel()->mgInfo->bots.contains(
|
||||
item->from()->asUser());
|
||||
}
|
||||
|
@ -1501,9 +1501,15 @@ void History::addItemsToLists(
|
|||
if (!lastKeyboardInited) {
|
||||
bool botNotInChat = false;
|
||||
if (peer->isChat()) {
|
||||
botNotInChat = (!peer->canWrite() || !peer->asChat()->participants.empty()) && item->author()->isUser() && !peer->asChat()->participants.contains(item->author()->asUser());
|
||||
botNotInChat = (!Data::CanSendAnything(peer)
|
||||
|| !peer->asChat()->participants.empty())
|
||||
&& item->author()->isUser()
|
||||
&& !peer->asChat()->participants.contains(item->author()->asUser());
|
||||
} else if (peer->isMegagroup()) {
|
||||
botNotInChat = (!peer->canWrite() || peer->asChannel()->mgInfo->botStatus != 0) && item->author()->isUser() && !peer->asChannel()->mgInfo->bots.contains(item->author()->asUser());
|
||||
botNotInChat = (!Data::CanSendAnything(peer)
|
||||
|| peer->asChannel()->mgInfo->botStatus != 0)
|
||||
&& item->author()->isUser()
|
||||
&& !peer->asChannel()->mgInfo->bots.contains(item->author()->asUser());
|
||||
}
|
||||
if (wasKeyboardHide || botNotInChat) {
|
||||
clearLastKeyboard();
|
||||
|
|
|
@ -2070,7 +2070,9 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
const auto canReply = [&] {
|
||||
const auto peer = item->history()->peer;
|
||||
const auto topic = item->topic();
|
||||
return topic ? topic->canWrite() : peer->canWrite();
|
||||
return topic
|
||||
? Data::CanSendAnything(topic)
|
||||
: Data::CanSendAnything(peer);
|
||||
}();
|
||||
if (canReply) {
|
||||
_menu->addAction(tr::lng_context_reply_msg(tr::now), [=] {
|
||||
|
|
|
@ -63,6 +63,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_game.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_group_call.h" // Data::GroupCall::id().
|
||||
#include "data/data_poll.h" // PollData::publicVotes.
|
||||
#include "data/data_sponsored_messages.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "chat_helpers/stickers_gift_box_pack.h"
|
||||
|
@ -1836,9 +1837,9 @@ bool HistoryItem::canBeEdited() const {
|
|||
if (isPost()) {
|
||||
return channel->canPublish();
|
||||
} else if (const auto topic = this->topic()) {
|
||||
return topic->canWrite();
|
||||
return Data::CanSendAnything(topic);
|
||||
} else {
|
||||
return channel->canWrite();
|
||||
return Data::CanSendAnything(channel);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1958,6 +1959,53 @@ bool HistoryItem::suggestDeleteAllReport() const {
|
|||
return !isPost() && !out();
|
||||
}
|
||||
|
||||
ChatRestriction HistoryItem::requiredSendRight() const {
|
||||
const auto media = this->media();
|
||||
if (media && media->game()) {
|
||||
return ChatRestriction::SendGames;
|
||||
}
|
||||
const auto photo = (media && !media->webpage())
|
||||
? media->photo()
|
||||
: nullptr;
|
||||
const auto document = (media && !media->webpage())
|
||||
? media->document()
|
||||
: nullptr;
|
||||
if (photo) {
|
||||
return ChatRestriction::SendPhotos;
|
||||
} else if (document) {
|
||||
return document->requiredSendRight();
|
||||
} else if (media && media->poll()) {
|
||||
return ChatRestriction::SendPolls;
|
||||
}
|
||||
return ChatRestriction::SendOther;
|
||||
}
|
||||
|
||||
bool HistoryItem::requiresSendInlineRight() const {
|
||||
return Has<HistoryMessageVia>();
|
||||
}
|
||||
|
||||
std::optional<QString> HistoryItem::errorTextForForward(
|
||||
not_null<Data::Thread*> to) const {
|
||||
const auto requiredRight = requiredSendRight();
|
||||
const auto requiresInline = requiresSendInlineRight();
|
||||
const auto peer = to->peer();
|
||||
constexpr auto kInline = ChatRestriction::SendInline;
|
||||
if (const auto error = Data::RestrictionError(peer, requiredRight)) {
|
||||
return *error;
|
||||
} else if (requiresInline && !Data::CanSend(to, kInline)) {
|
||||
return Data::RestrictionError(peer, kInline).value_or(
|
||||
tr::lng_forward_cant(tr::now));
|
||||
} else if (_media
|
||||
&& _media->poll()
|
||||
&& _media->poll()->publicVotes()
|
||||
&& peer->isBroadcast()) {
|
||||
return tr::lng_restricted_send_public_polls(tr::now);
|
||||
} else if (!Data::CanSend(to, requiredRight, false)) {
|
||||
return tr::lng_forward_cant(tr::now);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool HistoryItem::canReact() const {
|
||||
if (!isRegular() || isService()) {
|
||||
return false;
|
||||
|
|
|
@ -393,6 +393,10 @@ public:
|
|||
[[nodiscard]] bool suggestReport() const;
|
||||
[[nodiscard]] bool suggestBanReport() const;
|
||||
[[nodiscard]] bool suggestDeleteAllReport() const;
|
||||
[[nodiscard]] ChatRestriction requiredSendRight() const;
|
||||
[[nodiscard]] bool requiresSendInlineRight() const;
|
||||
[[nodiscard]] std::optional<QString> errorTextForForward(
|
||||
not_null<Data::Thread*> to) const;
|
||||
|
||||
[[nodiscard]] bool canReact() const;
|
||||
enum class ReactionSource {
|
||||
|
|
|
@ -41,15 +41,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] bool HasInlineItems(const HistoryItemsList &items) {
|
||||
for (const auto &item : items) {
|
||||
if (item->viaBot()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PeerCallKnown(not_null<PeerData*> peer) {
|
||||
if (peer->groupCall() != nullptr) {
|
||||
return true;
|
||||
|
@ -70,29 +61,28 @@ QString GetErrorTextForSending(
|
|||
const auto topic = forum
|
||||
? forum->topicFor(request.topicRootId)
|
||||
: nullptr;
|
||||
if (!(topic ? topic->canWrite() : peer->canWrite())) {
|
||||
return tr::lng_forward_cant(tr::now);
|
||||
}
|
||||
|
||||
const auto thread = topic
|
||||
? not_null<Data::Thread*>(topic)
|
||||
: peer->owner().history(peer);
|
||||
if (request.forward) {
|
||||
for (const auto &item : *request.forward) {
|
||||
if (const auto media = item->media()) {
|
||||
const auto error = media->errorTextForForward(peer);
|
||||
if (!error.isEmpty() && error != u"skip"_q) {
|
||||
return error;
|
||||
}
|
||||
if (const auto error = item->errorTextForForward(thread)) {
|
||||
return *error;
|
||||
}
|
||||
}
|
||||
}
|
||||
const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendInline);
|
||||
if (error && request.forward && HasInlineItems(*request.forward)) {
|
||||
return *error;
|
||||
const auto hasText = (request.text && !request.text->empty());
|
||||
if (hasText) {
|
||||
const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendOther);
|
||||
if (error) {
|
||||
return *error;
|
||||
} else if (!Data::CanSendTexts(thread)) {
|
||||
return tr::lng_forward_cant(tr::now);
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
|
|
@ -25,8 +25,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peers/edit_peer_requests_box.h"
|
||||
#include "core/file_utilities.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/toasts/common_toasts.h"
|
||||
#include "ui/emoji_config.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/chat/choose_theme_controller.h"
|
||||
|
@ -726,7 +724,7 @@ HistoryWidget::HistoryWidget(
|
|||
const auto account = &_peer->account();
|
||||
closeCurrent();
|
||||
if (const auto primary = Core::App().windowFor(account)) {
|
||||
primary->show(Ui::MakeInformBox(unavailable));
|
||||
controller->showToast({ unavailable });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -940,19 +938,14 @@ void HistoryWidget::initVoiceRecordBar() {
|
|||
if (_peer) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
_peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
return error;
|
||||
}
|
||||
if (const auto error = Data::RestrictionError(
|
||||
_peer,
|
||||
UserRestriction::SendVoiceMessages)) {
|
||||
ChatRestriction::SendVoiceMessages)) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}();
|
||||
if (error) {
|
||||
controller()->show(Ui::MakeInformBox(*error));
|
||||
controller()->showToast({ *error });
|
||||
return true;
|
||||
} else if (showSlowmodeError()) {
|
||||
return true;
|
||||
|
@ -1013,10 +1006,7 @@ void HistoryWidget::initVoiceRecordBar() {
|
|||
|
||||
_voiceRecordBar->recordingTipRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { tr::lng_record_hold_tip(tr::now) },
|
||||
});
|
||||
controller()->showToast({ tr::lng_record_hold_tip(tr::now) });
|
||||
}, lifetime());
|
||||
|
||||
_voiceRecordBar->hideFast();
|
||||
|
@ -1564,10 +1554,7 @@ void HistoryWidget::toggleChooseChatTheme(not_null<PeerData*> peer) {
|
|||
}
|
||||
return;
|
||||
} else if (_voiceRecordBar->isActive()) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { tr::lng_chat_theme_cant_voice(tr::now) },
|
||||
});
|
||||
controller()->showToast({ tr::lng_chat_theme_cant_voice(tr::now) });
|
||||
return;
|
||||
}
|
||||
_chooseTheme = std::make_unique<Ui::ChooseThemeController>(
|
||||
|
@ -2144,7 +2131,7 @@ void HistoryWidget::showHistory(
|
|||
|
||||
if (peerId) {
|
||||
_peer = session().data().peer(peerId);
|
||||
_canSendMessages = _peer->canWrite();
|
||||
_canSendMessages = Data::CanSendAnything(_peer);
|
||||
_contactStatus = std::make_unique<HistoryView::ContactStatus>(
|
||||
controller(),
|
||||
this,
|
||||
|
@ -2621,8 +2608,10 @@ bool HistoryWidget::canWriteMessage() const {
|
|||
}
|
||||
|
||||
std::optional<QString> HistoryWidget::writeRestriction() const {
|
||||
auto result = _peer
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendMessages)
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
auto result = (_peer && !Data::CanSendAnyOf(_peer, allWithoutPolls))
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendOther)
|
||||
: std::nullopt;
|
||||
if (result) {
|
||||
return result;
|
||||
|
@ -2827,7 +2816,15 @@ void HistoryWidget::updateControlsVisibility() {
|
|||
_botMenuButton->hide();
|
||||
}
|
||||
_kbScroll->hide();
|
||||
_fieldBarCancel->hide();
|
||||
if (_replyToId || readyToForward() || _kbReplyTo) {
|
||||
if (_fieldBarCancel->isHidden()) {
|
||||
_fieldBarCancel->show();
|
||||
updateControlsGeometry();
|
||||
update();
|
||||
}
|
||||
} else {
|
||||
_fieldBarCancel->hide();
|
||||
}
|
||||
_tabbedSelectorToggle->hide();
|
||||
_botKeyboardShow->hide();
|
||||
_botKeyboardHide->hide();
|
||||
|
@ -3010,12 +3007,9 @@ void HistoryWidget::messagesFailed(const MTP::Error &error, int requestId) {
|
|||
auto was = _peer;
|
||||
closeCurrent();
|
||||
if (const auto primary = Core::App().windowFor(&was->account())) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(primary).toastParent(),
|
||||
.text = { (was && was->isMegagroup())
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: tr::lng_channel_not_accessible(tr::now) },
|
||||
});
|
||||
controller()->showToast({ (was && was->isMegagroup())
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: tr::lng_channel_not_accessible(tr::now) });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -3653,8 +3647,9 @@ void HistoryWidget::saveEditMsg() {
|
|||
return;
|
||||
} else if (!left.text.isEmpty()) {
|
||||
const auto remove = left.text.size();
|
||||
controller()->show(Ui::MakeInformBox(
|
||||
tr::lng_edit_limit_reached(tr::now, lt_count, remove)));
|
||||
controller()->showToast({
|
||||
tr::lng_edit_limit_reached(tr::now, lt_count, remove)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3687,14 +3682,14 @@ void HistoryWidget::saveEditMsg() {
|
|||
_saveEditMsgRequestId = 0;
|
||||
}
|
||||
if (ranges::contains(Api::kDefaultEditMessagesErrors, error)) {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_error()));
|
||||
controller()->showToast({ tr::lng_edit_error(tr::now) });
|
||||
} else if (error == u"MESSAGE_NOT_MODIFIED"_q) {
|
||||
cancelEdit();
|
||||
} else if (error == u"MESSAGE_EMPTY"_q) {
|
||||
_field->selectAll();
|
||||
_field->setFocus();
|
||||
} else {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_error()));
|
||||
controller()->showToast({ tr::lng_edit_error(tr::now) });
|
||||
}
|
||||
update();
|
||||
})();
|
||||
|
@ -3796,27 +3791,12 @@ void HistoryWidget::send(Api::SendOptions options) {
|
|||
message.textWithTags = _field->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
|
||||
if (_canSendMessages) {
|
||||
const auto topicRootId = _replyEditMsg
|
||||
? _replyEditMsg->topicRootId()
|
||||
: 0;
|
||||
const auto error = GetErrorTextForSending(
|
||||
_peer,
|
||||
{
|
||||
.topicRootId = topicRootId,
|
||||
.forward = &_forwardPanel->items(),
|
||||
.text = &message.textWithTags,
|
||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { error },
|
||||
});
|
||||
return;
|
||||
}
|
||||
const auto ignoreSlowmodeCountdown = (options.scheduled != 0);
|
||||
if (showSendMessageError(
|
||||
message.textWithTags,
|
||||
ignoreSlowmodeCountdown)) {
|
||||
return;
|
||||
}
|
||||
|
||||
session().api().sendMessage(std::move(message));
|
||||
|
||||
clearFieldText();
|
||||
|
@ -3851,6 +3831,12 @@ void HistoryWidget::sendScheduled() {
|
|||
if (!_list) {
|
||||
return;
|
||||
}
|
||||
const auto ignoreSlowmodeCountdown = true;
|
||||
if (showSendMessageError(
|
||||
_field->getTextWithAppliedMarkdown(),
|
||||
ignoreSlowmodeCountdown)) {
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||
controller()->show(
|
||||
HistoryView::PrepareScheduleBox(_list, sendMenuType(), callback),
|
||||
|
@ -4127,19 +4113,14 @@ void HistoryWidget::finishAnimating() {
|
|||
void HistoryWidget::chooseAttach(
|
||||
std::optional<bool> overrideSendImagesAsPhotos) {
|
||||
if (_editMsgId) {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_caption_attach()));
|
||||
controller()->showToast({ tr::lng_edit_caption_attach(tr::now) });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_peer || !_canSendMessages) {
|
||||
return;
|
||||
} else if (const auto error = Data::RestrictionError(
|
||||
_peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { *error },
|
||||
});
|
||||
} else if (const auto error = Data::AnyFileRestrictionError(_peer)) {
|
||||
controller()->showToast({ *error });
|
||||
return;
|
||||
} else if (showSlowmodeError()) {
|
||||
return;
|
||||
|
@ -4371,9 +4352,8 @@ bool HistoryWidget::readyToForward() const {
|
|||
|
||||
bool HistoryWidget::hasSilentToggle() const {
|
||||
return _peer
|
||||
&& _peer->isChannel()
|
||||
&& !_peer->isMegagroup()
|
||||
&& _peer->canWrite()
|
||||
&& _peer->isBroadcast()
|
||||
&& Data::CanSendAnything(_peer)
|
||||
&& !session().data().notifySettings().silentPostsUnknown(_peer);
|
||||
}
|
||||
|
||||
|
@ -4421,7 +4401,7 @@ bool HistoryWidget::isChoosingTheme() const {
|
|||
bool HistoryWidget::isMuteUnmute() const {
|
||||
return _peer
|
||||
&& ((_peer->isBroadcast() && !_peer->asChannel()->canPublish())
|
||||
|| (_peer->isGigagroup() && !_peer->asChannel()->canWrite())
|
||||
|| (_peer->isGigagroup() && !Data::CanSendAnything(_peer))
|
||||
|| _peer->isRepliesChat());
|
||||
}
|
||||
|
||||
|
@ -4725,9 +4705,15 @@ void HistoryWidget::showMembersDropdown() {
|
|||
bool HistoryWidget::pushTabbedSelectorToThirdSection(
|
||||
not_null<Data::Thread*> thread,
|
||||
const Window::SectionShow ¶ms) {
|
||||
const auto selectorTypes = ChatRestriction::SendOther
|
||||
| ChatRestriction::SendInline
|
||||
| ChatRestriction::SendStickers
|
||||
| ChatRestriction::SendGifs;
|
||||
if (!_tabbedPanel) {
|
||||
return true;
|
||||
} else if (!thread->canWrite()) {
|
||||
} else if (!Data::CanSendAnyOf(
|
||||
thread,
|
||||
Data::TabbedPanelSendRestrictions())) {
|
||||
Core::App().settings().setTabbedReplacedWithInfo(true);
|
||||
controller()->showPeerInfo(thread, params.withThirdColumn());
|
||||
return false;
|
||||
|
@ -4978,19 +4964,18 @@ void HistoryWidget::updateFieldPlaceholder() {
|
|||
|
||||
bool HistoryWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list) const {
|
||||
return showSendingFilesError(list, std::nullopt);
|
||||
}
|
||||
|
||||
bool HistoryWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto error = _peer
|
||||
? Data::RestrictionError(
|
||||
_peer,
|
||||
ChatRestriction::SendMedia)
|
||||
? Data::FileRestrictionError(_peer, list, compress)
|
||||
: std::nullopt;
|
||||
if (error) {
|
||||
return *error;
|
||||
} else if (!canWriteMessage()) {
|
||||
return tr::lng_forward_send_files_cant(tr::now);
|
||||
}
|
||||
if (_peer->slowmodeApplied() && !list.canBeSentInSlowmode()) {
|
||||
return tr::lng_slowmode_no_many(tr::now);
|
||||
} else if (const auto left = _peer->slowmodeSecondsLeft()) {
|
||||
return tr::lng_slowmode_enabled(
|
||||
tr::now,
|
||||
|
@ -5017,11 +5002,31 @@ bool HistoryWidget::showSendingFilesError(
|
|||
controller()->show(Box(FileSizeLimitBox, &session(), fileSize));
|
||||
return true;
|
||||
}
|
||||
controller()->showToast({ text });
|
||||
return true;
|
||||
}
|
||||
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { text },
|
||||
});
|
||||
bool HistoryWidget::showSendMessageError(
|
||||
const TextWithTags &textWithTags,
|
||||
bool ignoreSlowmodeCountdown) const {
|
||||
if (!_canSendMessages) {
|
||||
return false;
|
||||
}
|
||||
const auto topicRootId = _replyEditMsg
|
||||
? _replyEditMsg->topicRootId()
|
||||
: 0;
|
||||
const auto error = GetErrorTextForSending(
|
||||
_peer,
|
||||
{
|
||||
.topicRootId = topicRootId,
|
||||
.forward = &_forwardPanel->items(),
|
||||
.text = &textWithTags,
|
||||
.ignoreSlowmodeCountdown = ignoreSlowmodeCountdown,
|
||||
});
|
||||
if (error.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
controller()->showToast({ error });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5045,11 +5050,10 @@ bool HistoryWidget::confirmSendingFiles(
|
|||
bool HistoryWidget::confirmSendingFiles(
|
||||
Ui::PreparedList &&list,
|
||||
const QString &insertTextOnCancel) {
|
||||
if (showSendingFilesError(list)) {
|
||||
return false;
|
||||
}
|
||||
if (_editMsgId) {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_caption_attach()));
|
||||
controller()->showToast({ tr::lng_edit_caption_attach(tr::now) });
|
||||
return false;
|
||||
} else if (showSendingFilesError(list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5061,7 +5065,8 @@ bool HistoryWidget::confirmSendingFiles(
|
|||
controller(),
|
||||
std::move(list),
|
||||
text,
|
||||
_peer,
|
||||
DefaultLimitsForPeer(_peer),
|
||||
DefaultCheckForPeer(controller(), _peer),
|
||||
Api::SendType::Normal,
|
||||
sendMenuType());
|
||||
_field->setTextWithTags({});
|
||||
|
@ -5106,16 +5111,15 @@ void HistoryWidget::sendingFilesConfirmed(
|
|||
bool ctrlShiftEnter) {
|
||||
Expects(list.filesToProcess.empty());
|
||||
|
||||
if (showSendingFilesError(list)) {
|
||||
const auto compress = way.sendImagesAsPhotos();
|
||||
if (showSendingFilesError(list, compress)) {
|
||||
return;
|
||||
}
|
||||
auto groups = DivideByGroups(
|
||||
std::move(list),
|
||||
way,
|
||||
_peer->slowmodeApplied());
|
||||
const auto type = way.sendImagesAsPhotos()
|
||||
? SendMediaType::Photo
|
||||
: SendMediaType::File;
|
||||
const auto type = compress ? SendMediaType::Photo : SendMediaType::File;
|
||||
auto action = prepareSendAction(options);
|
||||
action.clearDraft = false;
|
||||
if ((groups.size() != 1 || !groups.front().sentWithCaption())
|
||||
|
@ -5412,10 +5416,7 @@ int HistoryWidget::countInitialScrollTop() {
|
|||
const auto itemTop = _list->itemTop(item);
|
||||
if (itemTop < 0) {
|
||||
setMsgId(0);
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { tr::lng_message_not_found(tr::now) },
|
||||
});
|
||||
controller()->showToast({ tr::lng_message_not_found(tr::now) });
|
||||
return countInitialScrollTop();
|
||||
} else {
|
||||
const auto view = item->mainView();
|
||||
|
@ -6112,10 +6113,7 @@ bool HistoryWidget::showSlowmodeError() {
|
|||
if (text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { text },
|
||||
});
|
||||
controller()->showToast({ text });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6136,7 +6134,7 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
|
|||
|
||||
auto errorText = result.result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
controller()->show(Ui::MakeInformBox(errorText));
|
||||
controller()->showToast({ errorText });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6602,9 +6600,7 @@ bool HistoryWidget::sendExistingDocument(
|
|||
? Data::RestrictionError(_peer, ChatRestriction::SendStickers)
|
||||
: std::nullopt;
|
||||
if (error) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(*error),
|
||||
Ui::LayerOption::KeepOther);
|
||||
controller()->showToast({ *error });
|
||||
return false;
|
||||
} else if (!_peer
|
||||
|| !_canSendMessages
|
||||
|
@ -6636,12 +6632,10 @@ bool HistoryWidget::sendExistingPhoto(
|
|||
not_null<PhotoData*> photo,
|
||||
Api::SendOptions options) {
|
||||
const auto error = _peer
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendMedia)
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendPhotos)
|
||||
: std::nullopt;
|
||||
if (error) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(*error),
|
||||
Ui::LayerOption::KeepOther);
|
||||
controller()->showToast({ *error });
|
||||
return false;
|
||||
} else if (!_peer || !_canSendMessages) {
|
||||
return false;
|
||||
|
@ -6754,7 +6748,7 @@ void HistoryWidget::processReply() {
|
|||
return;
|
||||
} else if (_processingReplyItem->history() == _migrated) {
|
||||
if (_processingReplyItem->isService()) {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_reply_cant()));
|
||||
controller()->showToast({ tr::lng_reply_cant(tr::now) });
|
||||
} else {
|
||||
const auto itemId = _processingReplyItem->fullId();
|
||||
controller()->show(
|
||||
|
@ -6777,13 +6771,13 @@ void HistoryWidget::processReply() {
|
|||
if (forum->topicDeleted(topicRootId)) {
|
||||
return processCancel();
|
||||
} else if (const auto topic = forum->topicFor(topicRootId)) {
|
||||
if (!topic->canWrite()) {
|
||||
if (!Data::CanSendAnything(topic)) {
|
||||
return processCancel();
|
||||
}
|
||||
} else {
|
||||
forum->requestTopic(topicRootId, processContinue());
|
||||
}
|
||||
} else if (!_peer->canWrite()) {
|
||||
} else if (!Data::CanSendAnything(_peer)) {
|
||||
return processCancel();
|
||||
}
|
||||
setReplyFieldsFromProcessing();
|
||||
|
@ -6849,8 +6843,7 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
|
|||
} else if (_chooseTheme) {
|
||||
toggleChooseChatTheme(_peer);
|
||||
} else if (_voiceRecordBar->isActive()) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(tr::lng_edit_caption_voice()));
|
||||
controller()->showToast({ tr::lng_edit_caption_voice(tr::now) });
|
||||
return;
|
||||
} else if (_composeSearch) {
|
||||
_composeSearch->hideAnimated();
|
||||
|
@ -7264,9 +7257,11 @@ void HistoryWidget::handlePeerUpdate() {
|
|||
bool HistoryWidget::updateCanSendMessage() {
|
||||
const auto replyTo = (_replyToId && !_editMsgId) ? _replyEditMsg : 0;
|
||||
const auto topic = replyTo ? replyTo->topic() : nullptr;
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto newCanSendMessages = topic
|
||||
? topic->canWrite()
|
||||
: _peer->canWrite();
|
||||
? Data::CanSendAnyOf(topic, allWithoutPolls)
|
||||
: Data::CanSendAnyOf(_peer, allWithoutPolls);
|
||||
if (_canSendMessages == newCanSendMessages) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7740,9 +7735,17 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
|
|||
Painter p(this);
|
||||
const auto clip = e->rect();
|
||||
if (_list) {
|
||||
if (!_field->isHidden() || isRecording()) {
|
||||
const auto restrictionHidden = !_field->isHidden() || isRecording();
|
||||
if (restrictionHidden
|
||||
|| replyToId()
|
||||
|| readyToForward()
|
||||
|| _kbShown) {
|
||||
drawField(p, clip);
|
||||
} else if (const auto error = writeRestriction()) {
|
||||
}
|
||||
const auto error = restrictionHidden
|
||||
? std::nullopt
|
||||
: writeRestriction();
|
||||
if (error) {
|
||||
drawRestrictedWrite(p, *error);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -430,6 +430,12 @@ private:
|
|||
Ui::PreparedList &&list,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool showSendingFilesError(const Ui::PreparedList &list) const;
|
||||
bool showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const;
|
||||
bool showSendMessageError(
|
||||
const TextWithTags &textWithTags,
|
||||
bool ignoreSlowmodeCountdown) const;
|
||||
|
||||
void sendingFilesConfirmed(
|
||||
Ui::PreparedList &&list,
|
||||
|
|
|
@ -354,6 +354,7 @@ public:
|
|||
[[nodiscard]] bool isDisplayed() const;
|
||||
[[nodiscard]] bool isEditingMessage() const;
|
||||
[[nodiscard]] bool readyToForward() const;
|
||||
[[nodiscard]] const HistoryItemsList &forwardItems() const;
|
||||
[[nodiscard]] FullMsgId replyingToMessage() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> editMsgId() const;
|
||||
[[nodiscard]] rpl::producer<FullMsgId> scrollToItemRequests() const;
|
||||
|
@ -839,6 +840,10 @@ bool FieldHeader::readyToForward() const {
|
|||
return !_forwardPanel->empty();
|
||||
}
|
||||
|
||||
const HistoryItemsList &FieldHeader::forwardItems() const {
|
||||
return _forwardPanel->items();
|
||||
}
|
||||
|
||||
FullMsgId FieldHeader::replyingToMessage() const {
|
||||
return _replyToId.current();
|
||||
}
|
||||
|
@ -1057,6 +1062,10 @@ int ComposeControls::heightCurrent() const {
|
|||
: _wrap->height();
|
||||
}
|
||||
|
||||
const HistoryItemsList &ComposeControls::forwardItems() const {
|
||||
return _header->forwardItems();
|
||||
}
|
||||
|
||||
bool ComposeControls::focus() {
|
||||
if (isRecording()) {
|
||||
return false;
|
||||
|
@ -2061,12 +2070,12 @@ void ComposeControls::initSendButton() {
|
|||
void ComposeControls::initSendAsButton(not_null<PeerData*> peer) {
|
||||
using namespace rpl::mappers;
|
||||
|
||||
// SendAsPeers::shouldChoose checks PeerData::canWrite(false).
|
||||
// SendAsPeers::shouldChoose checks Data::CanSendAnything(PeerData*).
|
||||
rpl::combine(
|
||||
rpl::single(peer) | rpl::then(
|
||||
session().sendAsPeers().updated() | rpl::filter(_1 == peer)
|
||||
),
|
||||
Data::CanWriteValue(peer, false)
|
||||
Data::CanSendAnythingValue(peer, false)
|
||||
) | rpl::skip(1) | rpl::start_with_next([=] {
|
||||
if (updateSendAsButton()) {
|
||||
updateControlsVisibility();
|
||||
|
@ -2147,12 +2156,7 @@ void ComposeControls::initVoiceRecordBar() {
|
|||
if (!peer) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
return error;
|
||||
}
|
||||
if (const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
UserRestriction::SendVoiceMessages)) {
|
||||
ChatRestriction::SendVoiceMessages)) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
@ -2774,9 +2778,8 @@ bool ComposeControls::hasSilentBroadcastToggle() const {
|
|||
}
|
||||
const auto &peer = _history->peer;
|
||||
return peer
|
||||
&& peer->isChannel()
|
||||
&& !peer->isMegagroup()
|
||||
&& peer->canWrite()
|
||||
&& peer->isBroadcast()
|
||||
&& Data::CanSendAnything(peer)
|
||||
&& !session().data().notifySettings().silentPostsUnknown(peer);
|
||||
}
|
||||
|
||||
|
|
|
@ -150,6 +150,7 @@ public:
|
|||
|
||||
[[nodiscard]] bool isEditingMessage() const;
|
||||
[[nodiscard]] bool readyToForward() const;
|
||||
[[nodiscard]] const HistoryItemsList &forwardItems() const;
|
||||
[[nodiscard]] FullMsgId replyingToMessage() const;
|
||||
|
||||
[[nodiscard]] bool preventsClose(Fn<void()> &&continueCallback) const;
|
||||
|
|
|
@ -588,7 +588,9 @@ bool AddReplyToMessageAction(
|
|||
const auto peer = item ? item->history()->peer.get() : nullptr;
|
||||
if (!item
|
||||
|| !item->isRegular()
|
||||
|| (topic ? !topic->canWrite() : !peer->canWrite())
|
||||
|| !(topic
|
||||
? Data::CanSendAnything(topic)
|
||||
: Data::CanSendAnything(peer))
|
||||
|| (context != Context::History && context != Context::Replies)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2955,16 +2955,18 @@ bool Message::hasFastReply() const {
|
|||
}
|
||||
|
||||
bool Message::displayFastReply() const {
|
||||
const auto canWrite = [&] {
|
||||
const auto canSendAnything = [&] {
|
||||
const auto item = data();
|
||||
const auto peer = item->history()->peer;
|
||||
const auto topic = item->topic();
|
||||
return topic ? topic->canWrite() : peer->canWrite();
|
||||
return topic
|
||||
? Data::CanSendAnything(topic)
|
||||
: Data::CanSendAnything(peer);
|
||||
};
|
||||
|
||||
return hasFastReply()
|
||||
&& data()->isRegular()
|
||||
&& canWrite()
|
||||
&& canSendAnything()
|
||||
&& !delegate()->elementInSelectionMode();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "menu/menu_send.h" // SendMenu::Type.
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
|
@ -34,12 +35,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/item_text_options.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/effects/message_sending_animation_controller.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/toasts/common_toasts.h"
|
||||
#include "base/timer_rpl.h"
|
||||
#include "api/api_bot.h"
|
||||
#include "api/api_common.h"
|
||||
|
@ -687,18 +686,23 @@ void RepliesWidget::setupComposeControls() {
|
|||
session().changes().peerFlagsValue(
|
||||
_history->peer,
|
||||
Data::PeerUpdate::Flag::Rights),
|
||||
Data::CanWriteValue(_history->peer),
|
||||
Data::CanSendAnythingValue(_history->peer),
|
||||
std::move(topicWriteRestrictions)
|
||||
) | rpl::map([=](auto, auto, std::optional<QString> topicRestriction) {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto canSendAnything = _topic
|
||||
? Data::CanSendAnyOf(_topic, allWithoutPolls)
|
||||
: Data::CanSendAnyOf(_history->peer, allWithoutPolls);
|
||||
const auto restriction = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMessages);
|
||||
return restriction
|
||||
? restriction
|
||||
ChatRestriction::SendOther);
|
||||
return !canSendAnything
|
||||
? (restriction
|
||||
? restriction
|
||||
: tr::lng_group_not_accessible(tr::now))
|
||||
: topicRestriction
|
||||
? std::move(topicRestriction)
|
||||
: !(_topic ? _topic->canWrite() : _history->peer->canWrite())
|
||||
? tr::lng_group_not_accessible(tr::now)
|
||||
: std::optional<QString>();
|
||||
});
|
||||
|
||||
|
@ -841,7 +845,7 @@ void RepliesWidget::setupComposeControls() {
|
|||
channel->updateFull();
|
||||
if (!channel->isBroadcast()) {
|
||||
rpl::combine(
|
||||
Data::CanWriteValue(channel),
|
||||
Data::CanSendAnythingValue(channel),
|
||||
channel->flagsValue()
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshJoinGroupButton();
|
||||
|
@ -855,13 +859,8 @@ void RepliesWidget::setupComposeControls() {
|
|||
void RepliesWidget::chooseAttach(
|
||||
std::optional<bool> overrideSendImagesAsPhotos) {
|
||||
_choosingAttach = false;
|
||||
if (const auto error = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { *error },
|
||||
});
|
||||
if (const auto error = Data::AnyFileRestrictionError(_history->peer)) {
|
||||
controller()->showToast({ *error });
|
||||
return;
|
||||
} else if (showSlowmodeError()) {
|
||||
return;
|
||||
|
@ -945,7 +944,8 @@ bool RepliesWidget::confirmSendingFiles(
|
|||
controller(),
|
||||
std::move(list),
|
||||
_composeControls->getTextWithAppliedMarkdown(),
|
||||
_history->peer,
|
||||
DefaultLimitsForPeer(_history->peer),
|
||||
DefaultCheckForPeer(controller(), _history->peer),
|
||||
Api::SendType::Normal,
|
||||
SendMenu::Type::SilentOnly); // #TODO replies schedule
|
||||
|
||||
|
@ -980,7 +980,7 @@ void RepliesWidget::sendingFilesConfirmed(
|
|||
bool ctrlShiftEnter) {
|
||||
Expects(list.filesToProcess.empty());
|
||||
|
||||
if (showSendingFilesError(list)) {
|
||||
if (showSendingFilesError(list, way.sendImagesAsPhotos())) {
|
||||
return;
|
||||
}
|
||||
auto groups = DivideByGroups(
|
||||
|
@ -1051,19 +1051,10 @@ bool RepliesWidget::showSlowmodeError() {
|
|||
if (text.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { text },
|
||||
});
|
||||
controller()->showToast({ text });
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<QString> RepliesWidget::writeRestriction() const {
|
||||
return Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMessages);
|
||||
}
|
||||
|
||||
void RepliesWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
||||
if (item->history() == _history && item->inThread(_rootId)) {
|
||||
_cornerButtons.pushReplyReturn(item);
|
||||
|
@ -1095,16 +1086,17 @@ void RepliesWidget::uploadFile(
|
|||
|
||||
bool RepliesWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list) const {
|
||||
return showSendingFilesError(list, std::nullopt);
|
||||
}
|
||||
|
||||
bool RepliesWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto peer = _history->peer;
|
||||
const auto error = Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendMedia);
|
||||
const auto error = Data::FileRestrictionError(peer, list, compress);
|
||||
if (error) {
|
||||
return *error;
|
||||
}
|
||||
if (peer->slowmodeApplied() && !list.canBeSentInSlowmode()) {
|
||||
return tr::lng_slowmode_no_many(tr::now);
|
||||
} else if (const auto left = _history->peer->slowmodeSecondsLeft()) {
|
||||
return tr::lng_slowmode_enabled(
|
||||
tr::now,
|
||||
|
@ -1132,10 +1124,7 @@ bool RepliesWidget::showSendingFilesError(
|
|||
return true;
|
||||
}
|
||||
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { text },
|
||||
});
|
||||
controller()->showToast({ text });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1188,17 +1177,18 @@ void RepliesWidget::send(Api::SendOptions options) {
|
|||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
|
||||
//const auto error = GetErrorTextForSending(
|
||||
// _peer,
|
||||
// _toForward,
|
||||
// message.textWithTags);
|
||||
//if (!error.isEmpty()) {
|
||||
// Ui::ShowMultilineToast({
|
||||
// .parentOverride = Window::Show(controller()).toastParent(),
|
||||
// .text = { error },
|
||||
// });
|
||||
// return;
|
||||
//}
|
||||
const auto error = GetErrorTextForSending(
|
||||
_history->peer,
|
||||
{
|
||||
.topicRootId = _topic ? _topic->rootId() : MsgId(0),
|
||||
.forward = &_composeControls->forwardItems(),
|
||||
.text = &message.textWithTags,
|
||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
controller()->showToast({ error });
|
||||
return;
|
||||
}
|
||||
|
||||
session().api().sendMessage(std::move(message));
|
||||
|
||||
|
@ -1242,8 +1232,9 @@ void RepliesWidget::edit(
|
|||
return;
|
||||
} else if (!left.text.isEmpty()) {
|
||||
const auto remove = left.text.size();
|
||||
controller()->show(Ui::MakeInformBox(
|
||||
tr::lng_edit_limit_reached(tr::now, lt_count, remove)));
|
||||
controller()->showToast({
|
||||
tr::lng_edit_limit_reached(tr::now, lt_count, remove),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1267,13 +1258,13 @@ void RepliesWidget::edit(
|
|||
}
|
||||
|
||||
if (ranges::contains(Api::kDefaultEditMessagesErrors, error)) {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_error()));
|
||||
controller()->showToast({ tr::lng_edit_error(tr::now) });
|
||||
} else if (error == u"MESSAGE_NOT_MODIFIED"_q) {
|
||||
_composeControls->cancelEditMessage();
|
||||
} else if (error == u"MESSAGE_EMPTY"_q) {
|
||||
doSetInnerFocus();
|
||||
} else {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_error()));
|
||||
controller()->showToast({ tr::lng_edit_error(tr::now) });
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
|
@ -1311,10 +1302,10 @@ void RepliesWidget::refreshJoinGroupButton() {
|
|||
}
|
||||
};
|
||||
const auto channel = _history->peer->asChannel();
|
||||
const auto canWrite = !channel->isForum()
|
||||
? channel->canWrite()
|
||||
: (_topic && _topic->canWrite());
|
||||
if (channel->amIn() || canWrite) {
|
||||
const auto canSend = !channel->isForum()
|
||||
? Data::CanSendAnything(channel)
|
||||
: (_topic && Data::CanSendAnything(_topic));
|
||||
if (channel->amIn() || canSend) {
|
||||
set(nullptr);
|
||||
} else {
|
||||
if (!_joinGroup) {
|
||||
|
@ -1354,9 +1345,7 @@ bool RepliesWidget::sendExistingDocument(
|
|||
_history->peer,
|
||||
ChatRestriction::SendStickers);
|
||||
if (error) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(*error),
|
||||
Ui::LayerOption::KeepOther);
|
||||
controller()->showToast({ *error });
|
||||
return false;
|
||||
} else if (showSlowmodeError()
|
||||
|| ShowSendPremiumError(controller(), document)) {
|
||||
|
@ -1389,11 +1378,9 @@ bool RepliesWidget::sendExistingPhoto(
|
|||
Api::SendOptions options) {
|
||||
const auto error = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMedia);
|
||||
ChatRestriction::SendPhotos);
|
||||
if (error) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(*error),
|
||||
Ui::LayerOption::KeepOther);
|
||||
controller()->showToast({ *error });
|
||||
return false;
|
||||
} else if (showSlowmodeError()) {
|
||||
return false;
|
||||
|
@ -1413,7 +1400,7 @@ void RepliesWidget::sendInlineResult(
|
|||
not_null<UserData*> bot) {
|
||||
const auto errorText = result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
controller()->show(Ui::MakeInformBox(errorText));
|
||||
controller()->showToast({ errorText });
|
||||
return;
|
||||
}
|
||||
sendInlineResult(result, bot, {}, std::nullopt);
|
||||
|
|
|
@ -278,6 +278,9 @@ private:
|
|||
std::optional<bool> overrideSendImagesAsPhotos,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool showSendingFilesError(const Ui::PreparedList &list) const;
|
||||
bool showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const;
|
||||
void sendingFilesConfirmed(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
|
@ -307,7 +310,6 @@ private:
|
|||
void refreshJoinGroupButton();
|
||||
[[nodiscard]] bool emptyShown() const;
|
||||
[[nodiscard]] bool showSlowmodeError();
|
||||
[[nodiscard]] std::optional<QString> writeRestriction() const;
|
||||
|
||||
const not_null<History*> _history;
|
||||
MsgId _rootId = 0;
|
||||
|
|
|
@ -16,18 +16,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "menu/menu_send.h" // SendMenu::Type.
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/layers/generic_box.h"
|
||||
#include "ui/item_text_options.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/chat/attach/attach_send_files_way.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toasts/common_toasts.h"
|
||||
#include "api/api_common.h"
|
||||
#include "api/api_editing.h"
|
||||
#include "api/api_sending.h"
|
||||
|
@ -53,6 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_scheduled_messages.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "storage/storage_media_prepare.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "inline_bots/inline_bot_result.h"
|
||||
|
@ -199,7 +199,30 @@ ScheduledWidget::ScheduledWidget(
|
|||
ScheduledWidget::~ScheduledWidget() = default;
|
||||
|
||||
void ScheduledWidget::setupComposeControls() {
|
||||
_composeControls->setHistory({ .history = _history.get() });
|
||||
auto writeRestriction = rpl::combine(
|
||||
session().changes().peerFlagsValue(
|
||||
_history->peer,
|
||||
Data::PeerUpdate::Flag::Rights),
|
||||
Data::CanSendAnythingValue(_history->peer)
|
||||
) | rpl::map([=] {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto canSendAnything = Data::CanSendAnyOf(
|
||||
_history->peer,
|
||||
allWithoutPolls);
|
||||
const auto restriction = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendOther);
|
||||
return !canSendAnything
|
||||
? (restriction
|
||||
? restriction
|
||||
: tr::lng_group_not_accessible(tr::now))
|
||||
: std::optional<QString>();
|
||||
});
|
||||
_composeControls->setHistory({
|
||||
.history = _history.get(),
|
||||
.writeRestriction = std::move(writeRestriction),
|
||||
});
|
||||
|
||||
_composeControls->height(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -308,13 +331,8 @@ void ScheduledWidget::setupComposeControls() {
|
|||
}
|
||||
|
||||
void ScheduledWidget::chooseAttach() {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMedia)) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { *error },
|
||||
});
|
||||
if (const auto error = Data::AnyFileRestrictionError(_history->peer)) {
|
||||
controller()->showToast({ *error });
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -392,10 +410,11 @@ bool ScheduledWidget::confirmSendingFiles(
|
|||
controller(),
|
||||
std::move(list),
|
||||
_composeControls->getTextWithAppliedMarkdown(),
|
||||
_history->peer,
|
||||
CanScheduleUntilOnline(_history->peer)
|
||||
DefaultLimitsForPeer(_history->peer),
|
||||
DefaultCheckForPeer(controller(), _history->peer),
|
||||
(CanScheduleUntilOnline(_history->peer)
|
||||
? Api::SendType::ScheduledToUser
|
||||
: Api::SendType::Scheduled,
|
||||
: Api::SendType::Scheduled),
|
||||
SendMenu::Type::Disabled);
|
||||
|
||||
box->setConfirmedCallback(crl::guard(this, [=](
|
||||
|
@ -429,7 +448,7 @@ void ScheduledWidget::sendingFilesConfirmed(
|
|||
bool ctrlShiftEnter) {
|
||||
Expects(list.filesToProcess.empty());
|
||||
|
||||
if (showSendingFilesError(list)) {
|
||||
if (showSendingFilesError(list, way.sendImagesAsPhotos())) {
|
||||
return;
|
||||
}
|
||||
auto groups = DivideByGroups(std::move(list), way, false);
|
||||
|
@ -512,15 +531,19 @@ void ScheduledWidget::uploadFile(
|
|||
|
||||
bool ScheduledWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list) const {
|
||||
return showSendingFilesError(list, std::nullopt);
|
||||
}
|
||||
|
||||
bool ScheduledWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto error = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMedia);
|
||||
using Error = Ui::PreparedList::Error;
|
||||
const auto peer = _history->peer;
|
||||
const auto error = Data::FileRestrictionError(peer, list, compress);
|
||||
if (error) {
|
||||
return *error;
|
||||
}
|
||||
using Error = Ui::PreparedList::Error;
|
||||
switch (list.error) {
|
||||
} else switch (list.error) {
|
||||
case Error::None: return QString();
|
||||
case Error::EmptyFile:
|
||||
case Error::Directory:
|
||||
|
@ -540,10 +563,7 @@ bool ScheduledWidget::showSendingFilesError(
|
|||
return true;
|
||||
}
|
||||
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(controller()).toastParent(),
|
||||
.text = { text },
|
||||
});
|
||||
controller()->showToast({ text });
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -555,7 +575,21 @@ Api::SendAction ScheduledWidget::prepareSendAction(
|
|||
}
|
||||
|
||||
void ScheduledWidget::send() {
|
||||
if (_composeControls->getTextWithAppliedMarkdown().text.isEmpty()) {
|
||||
const auto textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
if (textWithTags.text.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto error = GetErrorTextForSending(
|
||||
_history->peer,
|
||||
{
|
||||
.topicRootId = MsgId(),
|
||||
.forward = nullptr,
|
||||
.text = &textWithTags,
|
||||
.ignoreSlowmodeCountdown = true,
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
controller()->showToast({ error });
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||
|
@ -571,18 +605,6 @@ void ScheduledWidget::send(Api::SendOptions options) {
|
|||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
message.webPageId = webPageId;
|
||||
|
||||
//const auto error = GetErrorTextForSending(
|
||||
// _peer,
|
||||
// _toForward,
|
||||
// message.textWithTags);
|
||||
//if (!error.isEmpty()) {
|
||||
// Ui::ShowMultilineToast({
|
||||
// .parentOverride = Window::Show(controller()).toastParent(),
|
||||
// .text = { error },
|
||||
// });
|
||||
// return;
|
||||
//}
|
||||
|
||||
session().api().sendMessage(std::move(message));
|
||||
|
||||
_composeControls->clear();
|
||||
|
@ -647,8 +669,9 @@ void ScheduledWidget::edit(
|
|||
return;
|
||||
} else if (!left.text.isEmpty()) {
|
||||
const auto remove = left.text.size();
|
||||
controller()->show(Ui::MakeInformBox(
|
||||
tr::lng_edit_limit_reached(tr::now, lt_count, remove)));
|
||||
controller()->showToast({
|
||||
tr::lng_edit_limit_reached(tr::now, lt_count, remove)
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -672,13 +695,13 @@ void ScheduledWidget::edit(
|
|||
}
|
||||
|
||||
if (ranges::contains(Api::kDefaultEditMessagesErrors, error)) {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_error()));
|
||||
controller()->showToast({ tr::lng_edit_error(tr::now) });
|
||||
} else if (error == u"MESSAGE_NOT_MODIFIED"_q) {
|
||||
_composeControls->cancelEditMessage();
|
||||
} else if (error == u"MESSAGE_EMPTY"_q) {
|
||||
_composeControls->focus();
|
||||
} else {
|
||||
controller()->show(Ui::MakeInformBox(tr::lng_edit_error()));
|
||||
controller()->showToast({ tr::lng_edit_error(tr::now) });
|
||||
}
|
||||
update();
|
||||
return true;
|
||||
|
@ -712,9 +735,7 @@ bool ScheduledWidget::sendExistingDocument(
|
|||
_history->peer,
|
||||
ChatRestriction::SendStickers);
|
||||
if (error) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(*error),
|
||||
Ui::LayerOption::KeepOther);
|
||||
controller()->showToast({ *error });
|
||||
return false;
|
||||
} else if (ShowSendPremiumError(controller(), document)) {
|
||||
return false;
|
||||
|
@ -743,11 +764,9 @@ bool ScheduledWidget::sendExistingPhoto(
|
|||
Api::SendOptions options) {
|
||||
const auto error = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendMedia);
|
||||
ChatRestriction::SendPhotos);
|
||||
if (error) {
|
||||
controller()->show(
|
||||
Ui::MakeInformBox(*error),
|
||||
Ui::LayerOption::KeepOther);
|
||||
controller()->showToast({ *error });
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -765,7 +784,7 @@ void ScheduledWidget::sendInlineResult(
|
|||
not_null<UserData*> bot) {
|
||||
const auto errorText = result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
controller()->show(Ui::MakeInformBox(errorText));
|
||||
controller()->showToast({ errorText });
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Api::SendOptions options) {
|
||||
|
|
|
@ -224,6 +224,9 @@ private:
|
|||
std::optional<bool> overrideSendImagesAsPhotos,
|
||||
const QString &insertTextOnCancel = QString());
|
||||
bool showSendingFilesError(const Ui::PreparedList &list) const;
|
||||
bool showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const;
|
||||
void sendingFilesConfirmed(
|
||||
Ui::PreparedList &&list,
|
||||
Ui::SendFilesWay way,
|
||||
|
|
|
@ -1033,8 +1033,8 @@ void TopBarWidget::updateControlsVisibility() {
|
|||
const auto section = _activeChat.section;
|
||||
const auto historyMode = (section == Section::History);
|
||||
const auto hasPollsMenu = (_activeChat.key.peer()
|
||||
&& _activeChat.key.peer()->canSendPolls())
|
||||
|| (topic && topic->canSendPolls());
|
||||
&& Data::CanSend(_activeChat.key.peer(), ChatRestriction::SendPolls))
|
||||
|| (topic && Data::CanSend(topic, ChatRestriction::SendPolls));
|
||||
const auto hasTopicMenu = [&] {
|
||||
if (!topic || section != Section::Replies) {
|
||||
return false;
|
||||
|
|
|
@ -145,7 +145,7 @@ void ShowChooseBox(
|
|||
};
|
||||
auto filter = [=](not_null<Data::Thread*> thread) -> bool {
|
||||
const auto peer = thread->peer();
|
||||
if (!thread->canWrite()) {
|
||||
if (!Data::CanSend(thread, ChatRestriction::SendInline, false)) {
|
||||
return false;
|
||||
} else if (const auto user = peer->asUser()) {
|
||||
if (user->isBot()) {
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_file_origin.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_reply_markup.h"
|
||||
#include "inline_bots/inline_bot_layout_item.h"
|
||||
#include "inline_bots/inline_bot_send_data.h"
|
||||
|
@ -367,7 +368,7 @@ bool Result::hasThumbDisplay() const {
|
|||
};
|
||||
|
||||
void Result::addToHistory(
|
||||
History *history,
|
||||
not_null<History*> history,
|
||||
MessageFlags flags,
|
||||
MsgId msgId,
|
||||
PeerId fromId,
|
||||
|
@ -394,8 +395,13 @@ void Result::addToHistory(
|
|||
std::move(markup));
|
||||
}
|
||||
|
||||
QString Result::getErrorOnSend(History *history) const {
|
||||
return sendData->getErrorOnSend(this, history);
|
||||
QString Result::getErrorOnSend(not_null<History*> history) const {
|
||||
const auto specific = sendData->getErrorOnSend(this, history);
|
||||
return !specific.isEmpty()
|
||||
? specific
|
||||
: Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendInline).value_or(QString());
|
||||
}
|
||||
|
||||
std::optional<Data::LocationPoint> Result::getLocationPoint() const {
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
bool hasThumbDisplay() const;
|
||||
|
||||
void addToHistory(
|
||||
History *history,
|
||||
not_null<History*> history,
|
||||
MessageFlags flags,
|
||||
MsgId msgId,
|
||||
PeerId fromId,
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
UserId viaBotId,
|
||||
MsgId replyToId,
|
||||
const QString &postAuthor) const;
|
||||
QString getErrorOnSend(History *history) const;
|
||||
QString getErrorOnSend(not_null<History*> history) const;
|
||||
|
||||
// interface for Layout:: usage
|
||||
std::optional<Data::LocationPoint> getLocationPoint() const;
|
||||
|
|
|
@ -59,10 +59,8 @@ void SendDataCommon::addToHistory(
|
|||
QString SendDataCommon::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto error = Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendMessages);
|
||||
return error.value_or(QString());
|
||||
const auto type = ChatRestriction::SendOther;
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
}
|
||||
|
||||
SendDataCommon::SentMessageFields SendText::getSentMessageFields() const {
|
||||
|
@ -140,10 +138,8 @@ void SendPhoto::addToHistory(
|
|||
QString SendPhoto::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto error = Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendMedia);
|
||||
return error.value_or(QString());
|
||||
const auto type = ChatRestriction::SendPhotos;
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
}
|
||||
|
||||
void SendFile::addToHistory(
|
||||
|
@ -173,24 +169,8 @@ void SendFile::addToHistory(
|
|||
QString SendFile::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto errorMedia = Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendMedia);
|
||||
const auto errorStickers = Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendStickers);
|
||||
const auto errorGifs = Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendGifs);
|
||||
return errorMedia
|
||||
? *errorMedia
|
||||
: (errorStickers && (_document->sticker() != nullptr))
|
||||
? *errorStickers
|
||||
: (errorGifs
|
||||
&& _document->isAnimation()
|
||||
&& !_document->isVideoMessage())
|
||||
? *errorGifs
|
||||
: QString();
|
||||
const auto type = _document->requiredSendRight();
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
}
|
||||
|
||||
void SendGame::addToHistory(
|
||||
|
@ -219,10 +199,8 @@ void SendGame::addToHistory(
|
|||
QString SendGame::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto error = Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendGames);
|
||||
return error.value_or(QString());
|
||||
const auto type = ChatRestriction::SendGames;
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
}
|
||||
|
||||
SendDataCommon::SentMessageFields SendInvoice::getSentMessageFields() const {
|
||||
|
|
|
@ -43,7 +43,7 @@ SendAsPeers::SendAsPeers(not_null<Session*> session)
|
|||
|
||||
bool SendAsPeers::shouldChoose(not_null<PeerData*> peer) {
|
||||
refresh(peer);
|
||||
return peer->canWrite(false) && (list(peer).size() > 1);
|
||||
return Data::CanSendAnything(peer, false) && (list(peer).size() > 1);
|
||||
}
|
||||
|
||||
void SendAsPeers::refresh(not_null<PeerData*> peer, bool force) {
|
||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_user.h"
|
||||
|
@ -363,9 +364,13 @@ MainWidget::MainWidget(
|
|||
const auto peer = key.peer();
|
||||
const auto topic = key.topic();
|
||||
auto canWrite = topic
|
||||
? Data::CanWriteValue(topic)
|
||||
? Data::CanSendAnyOfValue(
|
||||
topic,
|
||||
Data::TabbedPanelSendRestrictions())
|
||||
: peer
|
||||
? Data::CanWriteValue(peer)
|
||||
? Data::CanSendAnyOfValue(
|
||||
|
||||
peer, Data::TabbedPanelSendRestrictions())
|
||||
: rpl::single(false);
|
||||
return std::move(
|
||||
canWrite
|
||||
|
@ -559,7 +564,7 @@ bool MainWidget::setForwardDraft(
|
|||
.ignoreSlowmodeCountdown = true,
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
Ui::show(Ui::MakeInformBox(error), Ui::LayerOption::KeepOther);
|
||||
_controller->show(Ui::MakeInformBox(error));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -575,7 +580,7 @@ bool MainWidget::shareUrl(
|
|||
not_null<Data::Thread*> thread,
|
||||
const QString &url,
|
||||
const QString &text) const {
|
||||
if (!thread->canWrite()) {
|
||||
if (!Data::CanSendTexts(thread)) {
|
||||
_controller->show(Ui::MakeInformBox(tr::lng_share_cant()));
|
||||
return false;
|
||||
}
|
||||
|
@ -606,8 +611,8 @@ bool MainWidget::shareUrl(
|
|||
bool MainWidget::inlineSwitchChosen(
|
||||
not_null<Data::Thread*> thread,
|
||||
const QString &botAndQuery) const {
|
||||
if (!thread->canWrite()) {
|
||||
Ui::show(Ui::MakeInformBox(tr::lng_inline_switch_cant()));
|
||||
if (!Data::CanSend(thread, ChatRestriction::SendInline)) {
|
||||
_controller->show(Ui::MakeInformBox(tr::lng_inline_switch_cant()));
|
||||
return false;
|
||||
}
|
||||
const auto textWithTags = TextWithTags{
|
||||
|
@ -637,13 +642,13 @@ bool MainWidget::inlineSwitchChosen(
|
|||
bool MainWidget::sendPaths(
|
||||
not_null<Data::Thread*> thread,
|
||||
const QStringList &paths) {
|
||||
if (!thread->canWrite()) {
|
||||
Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant()));
|
||||
if (!Data::CanSendAnyOf(thread, Data::FilesSendRestrictions())) {
|
||||
_controller->show(Ui::MakeInformBox(
|
||||
tr::lng_forward_send_files_cant()));
|
||||
return false;
|
||||
} else if (const auto error = Data::RestrictionError(
|
||||
thread->peer(),
|
||||
ChatRestriction::SendMedia)) {
|
||||
Ui::show(Ui::MakeInformBox(*error));
|
||||
} else if (const auto error = Data::AnyFileRestrictionError(
|
||||
thread->peer())) {
|
||||
_controller->show(Ui::MakeInformBox(*error));
|
||||
return false;
|
||||
} else {
|
||||
_controller->showThread(
|
||||
|
@ -685,8 +690,13 @@ bool MainWidget::filesOrForwardDrop(
|
|||
clearHider(_hider);
|
||||
}
|
||||
return false;
|
||||
} else if (!thread->canWrite()) {
|
||||
Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant()));
|
||||
} else if (!Data::CanSendAnyOf(thread, Data::FilesSendRestrictions())) {
|
||||
_controller->show(Ui::MakeInformBox(
|
||||
tr::lng_forward_send_files_cant()));
|
||||
return false;
|
||||
} else if (const auto error = Data::AnyFileRestrictionError(
|
||||
thread->peer())) {
|
||||
_controller->show(Ui::MakeInformBox(*error));
|
||||
return false;
|
||||
} else {
|
||||
_controller->showThread(
|
||||
|
@ -2111,7 +2121,8 @@ void MainWidget::hideAll() {
|
|||
void MainWidget::showAll() {
|
||||
if (cPasswordRecovered()) {
|
||||
cSetPasswordRecovered(false);
|
||||
Ui::show(Ui::MakeInformBox(tr::lng_cloud_password_updated()));
|
||||
_controller->show(Ui::MakeInformBox(
|
||||
tr::lng_cloud_password_updated()));
|
||||
}
|
||||
if (isOneColumn()) {
|
||||
if (_sideShadow) {
|
||||
|
@ -2720,7 +2731,7 @@ void MainWidget::activate() {
|
|||
_controller,
|
||||
paths[0].mid(interpret.size()));
|
||||
if (!error.isEmpty()) {
|
||||
Ui::show(Ui::MakeInformBox(error));
|
||||
_controller->show(Ui::MakeInformBox(error));
|
||||
}
|
||||
} else {
|
||||
const auto chosen = [=](not_null<Data::Thread*> thread) {
|
||||
|
|
|
@ -168,25 +168,22 @@ auto ActiveChat(not_null<Window::Controller*> controller) {
|
|||
return Dialogs::Key();
|
||||
}
|
||||
|
||||
bool CanWriteToActiveChat(not_null<Window::Controller*> controller) {
|
||||
bool CanSendToActiveChat(
|
||||
not_null<Window::Controller*> controller,
|
||||
ChatRestriction right) {
|
||||
if (const auto topic = ActiveChat(controller).topic()) {
|
||||
return topic->canWrite();
|
||||
return Data::CanSend(topic, right);
|
||||
} else if (const auto history = ActiveChat(controller).history()) {
|
||||
return history->peer->canWrite();
|
||||
return Data::CanSend(history->peer, right);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<QString> RestrictionToSendStickers(not_null<PeerData*> peer) {
|
||||
return Data::RestrictionError(
|
||||
peer,
|
||||
ChatRestriction::SendStickers);
|
||||
}
|
||||
|
||||
std::optional<QString> RestrictionToSendStickers(
|
||||
not_null<Window::Controller*> controller) {
|
||||
std::optional<QString> RestrictionToSend(
|
||||
not_null<Window::Controller*> controller,
|
||||
ChatRestriction right) {
|
||||
if (const auto peer = ActiveChat(controller).peer()) {
|
||||
return RestrictionToSendStickers(peer);
|
||||
return Data::RestrictionError(peer, right);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -364,10 +361,17 @@ void AppendEmojiPacks(
|
|||
gesture.allowableMovement = 0;
|
||||
[scrubber addGestureRecognizer:gesture];
|
||||
|
||||
if (const auto error = RestrictionToSendStickers(_controller)) {
|
||||
const auto kRight = ChatRestriction::SendStickers;
|
||||
if (const auto error = RestrictionToSend(_controller, kRight)) {
|
||||
_error = std::make_unique<PickerScrubberItem>(
|
||||
tr::lng_restricted_send_stickers_all(tr::now));
|
||||
}
|
||||
} else {
|
||||
const auto kRight = ChatRestriction::SendOther;
|
||||
if (const auto error = RestrictionToSend(_controller, kRight)) {
|
||||
_error = std::make_unique<PickerScrubberItem>(
|
||||
tr::lng_restricted_send_message_all(tr::now));
|
||||
}
|
||||
}
|
||||
_lastPreviewedSticker = 0;
|
||||
|
||||
|
@ -467,16 +471,19 @@ void AppendEmojiPacks(
|
|||
|
||||
- (void)scrubber:(NSScrubber*)scrubber
|
||||
didSelectItemAtIndex:(NSInteger)index {
|
||||
if (!CanWriteToActiveChat(_controller) || _error) {
|
||||
return;
|
||||
}
|
||||
scrubber.selectedIndex = -1;
|
||||
const auto sticker = _itemsDataSource->at(index, _type);
|
||||
const auto document = sticker.document;
|
||||
const auto emoji = sticker.emoji;
|
||||
const auto kRight = document
|
||||
? ChatRestriction::SendStickers
|
||||
: ChatRestriction::SendOther;
|
||||
if (!CanSendToActiveChat(_controller, kRight) || _error) {
|
||||
return;
|
||||
}
|
||||
auto callback = [=] {
|
||||
if (document) {
|
||||
if (const auto error = RestrictionToSendStickers(_controller)) {
|
||||
if (const auto error = RestrictionToSend(_controller, kRight)) {
|
||||
_controller->show(Ui::MakeInformBox(*error));
|
||||
return true;
|
||||
} else if (Window::ShowSendPremiumError(_controller->sessionController(), document)) {
|
||||
|
@ -488,7 +495,10 @@ void AppendEmojiPacks(
|
|||
document);
|
||||
return true;
|
||||
} else if (emoji) {
|
||||
if (const auto inputField = qobject_cast<QTextEdit*>(
|
||||
if (const auto error = RestrictionToSend(_controller, kRight)) {
|
||||
_controller->show(Ui::MakeInformBox(*error));
|
||||
return true;
|
||||
} else if (const auto inputField = qobject_cast<QTextEdit*>(
|
||||
QApplication::focusWidget())) {
|
||||
Ui::InsertEmojiAtCursor(inputField->textCursor(), emoji);
|
||||
Core::App().settings().incrementRecentEmoji({ emoji });
|
||||
|
@ -562,9 +572,11 @@ void AppendEmojiPacks(
|
|||
) | rpl::map([](Dialogs::Key k) {
|
||||
const auto topic = k.topic();
|
||||
const auto peer = k.peer();
|
||||
const auto right = ChatRestriction::SendStickers;
|
||||
return peer
|
||||
&& !RestrictionToSendStickers(peer)
|
||||
&& (topic ? topic->canWrite() : peer->canWrite());
|
||||
&& (topic
|
||||
? Data::CanSend(topic, right)
|
||||
: Data::CanSend(peer, right));
|
||||
}) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](bool value) {
|
||||
[self dismissPopover:nil];
|
||||
|
|
|
@ -9,8 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "apiwrap.h" // ApiWrap::updateStickers()
|
||||
#include "core/application.h"
|
||||
#include "data/data_peer.h" // PeerData::canWrite()
|
||||
#include "data/data_forum_topic.h" // Data::ForumTopic::canWrite()
|
||||
#include "data/data_chat_participant_status.h" // Data::CanSendAnyOf.
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_stickers.h" // Stickers::setsRef()
|
||||
#include "main/main_domain.h"
|
||||
|
@ -146,9 +145,11 @@ const auto kAudioItemIdentifier = @"touchbarAudio";
|
|||
) | rpl::map([](Dialogs::Key k) {
|
||||
const auto topic = k.topic();
|
||||
const auto peer = k.peer();
|
||||
const auto rights = ChatRestriction::SendStickers
|
||||
| ChatRestriction::SendOther;
|
||||
return topic
|
||||
? topic->canWrite()
|
||||
: (peer && peer->canWrite());
|
||||
? Data::CanSendAnyOf(topic, rights)
|
||||
: (peer && Data::CanSendAnyOf(peer, rights));
|
||||
}) | rpl::distinct_until_changed()
|
||||
) | rpl::start_with_next([=](
|
||||
bool canApplyMarkdown,
|
||||
|
|
|
@ -35,6 +35,22 @@ bool PreparedFile::canBeInAlbumType(AlbumType album) const {
|
|||
return CanBeInAlbumType(type, album);
|
||||
}
|
||||
|
||||
bool PreparedFile::isSticker() const {
|
||||
Expects(information != nullptr);
|
||||
|
||||
return (type == PreparedFile::Type::Photo)
|
||||
&& Core::IsMimeSticker(information->filemime);
|
||||
}
|
||||
|
||||
bool PreparedFile::isGifv() const {
|
||||
Expects(information != nullptr);
|
||||
|
||||
using Video = Ui::PreparedFileInformation::Video;
|
||||
return (type == PreparedFile::Type::Video)
|
||||
&& v::is<Video>(information->media)
|
||||
&& v::get<Video>(information->media).isGifv;
|
||||
}
|
||||
|
||||
AlbumType PreparedFile::albumType(bool sendImagesAsPhotos) const {
|
||||
switch (type) {
|
||||
case Type::Photo:
|
||||
|
@ -207,13 +223,7 @@ bool PreparedList::canHaveEditorHintLabel() const {
|
|||
}
|
||||
|
||||
bool PreparedList::hasSticker() const {
|
||||
for (const auto &file : files) {
|
||||
if ((file.type == PreparedFile::Type::Photo)
|
||||
&& Core::IsMimeSticker(file.information->filemime)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return ranges::any_of(files, &PreparedFile::isSticker);
|
||||
}
|
||||
|
||||
int MaxAlbumItems() {
|
||||
|
|
|
@ -73,6 +73,8 @@ struct PreparedFile {
|
|||
|
||||
[[nodiscard]] bool canBeInAlbumType(AlbumType album) const;
|
||||
[[nodiscard]] AlbumType albumType(bool sendImagesAsPhotos) const;
|
||||
[[nodiscard]] bool isSticker() const;
|
||||
[[nodiscard]] bool isGifv() const;
|
||||
|
||||
QString path;
|
||||
QByteArray content;
|
||||
|
|
|
@ -836,7 +836,8 @@ Manager::DisplayOptions Manager::getNotificationOptions(
|
|||
|| !item
|
||||
|| ((item->out() || peer->isSelf()) && item->isFromScheduled());
|
||||
result.hideReplyButton = result.hideMarkAsRead
|
||||
|| (!peer->canWrite() && (!topic || !topic->canWrite()))
|
||||
|| (!Data::CanSendTexts(peer)
|
||||
&& (!topic || !Data::CanSendTexts(topic)))
|
||||
|| peer->isBroadcast()
|
||||
|| (peer->slowmodeSecondsLeft() > 0);
|
||||
return result;
|
||||
|
|
|
@ -951,7 +951,11 @@ void Filler::addManageChat() {
|
|||
}
|
||||
|
||||
void Filler::addCreatePoll() {
|
||||
if (!(_topic ? _topic->canSendPolls() : _peer->canSendPolls())) {
|
||||
constexpr auto kRight = ChatRestriction::SendPolls;
|
||||
const auto can = _topic
|
||||
? Data::CanSend(_topic, kRight)
|
||||
: Data::CanSend(_peer, kRight);
|
||||
if (!can) {
|
||||
return;
|
||||
}
|
||||
const auto peer = _peer;
|
||||
|
@ -1329,7 +1333,7 @@ void PeerMenuShareContactBox(
|
|||
const auto weak = std::make_shared<QPointer<Ui::BoxContent>>();
|
||||
auto callback = [=](not_null<Data::Thread*> thread) {
|
||||
const auto peer = thread->peer();
|
||||
if (!thread->canWrite()) {
|
||||
if (!Data::CanSend(thread, ChatRestriction::SendOther)) {
|
||||
navigation->parentController()->show(
|
||||
Ui::MakeInformBox(tr::lng_forward_share_cant()),
|
||||
Ui::LayerOption::KeepOther);
|
||||
|
@ -1946,10 +1950,9 @@ QPointer<Ui::BoxContent> ShowShareGameBox(
|
|||
Ui::LayerOption::KeepOther);
|
||||
};
|
||||
auto filter = [](not_null<Data::Thread*> thread) {
|
||||
const auto peer = thread->peer();
|
||||
return (thread->canWrite() || thread->asForum())
|
||||
&& !peer->amRestricted(ChatRestriction::SendGames)
|
||||
&& !peer->isSelf();
|
||||
return !thread->peer()->isSelf()
|
||||
&& (Data::CanSend(thread, ChatRestriction::SendGames)
|
||||
|| thread->asForum());
|
||||
};
|
||||
auto initBox = [](not_null<PeerListBox*> box) {
|
||||
box->addButton(tr::lng_cancel(), [box] {
|
||||
|
|
|
@ -1871,6 +1871,13 @@ void SessionController::hideLayer(anim::type animated) {
|
|||
_window->hideLayer(animated);
|
||||
}
|
||||
|
||||
void SessionController::showToast(TextWithEntities &&text) {
|
||||
Ui::ShowMultilineToast({
|
||||
.parentOverride = Window::Show(this).toastParent(),
|
||||
.text = std::move(text),
|
||||
});
|
||||
}
|
||||
|
||||
void SessionController::openPhoto(
|
||||
not_null<PhotoData*> photo,
|
||||
FullMsgId contextId,
|
||||
|
|
|
@ -337,9 +337,10 @@ public:
|
|||
object_ptr<Ui::BoxContent> content,
|
||||
Ui::LayerOptions options = Ui::LayerOption::KeepOther,
|
||||
anim::type animated = anim::type::normal);
|
||||
|
||||
void hideLayer(anim::type animated = anim::type::normal);
|
||||
|
||||
void showToast(TextWithEntities &&text);
|
||||
|
||||
[[nodiscard]] auto sendingAnimation() const
|
||||
-> Ui::MessageSendingAnimationController &;
|
||||
[[nodiscard]] auto tabbedSelector() const
|
||||
|
|
Loading…
Add table
Reference in a new issue