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