mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Ask for boosts to unlock group restrictions.
This commit is contained in:
parent
a7ae7a8cda
commit
5f10c1875c
38 changed files with 587 additions and 389 deletions
|
@ -3267,13 +3267,13 @@ void ApiWrap::finishForwarding(const SendAction &action) {
|
|||
const auto topicRootId = action.replyTo.topicRootId;
|
||||
auto toForward = history->resolveForwardDraft(topicRootId);
|
||||
if (!toForward.items.empty()) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
history->peer,
|
||||
{
|
||||
.topicRootId = topicRootId,
|
||||
.forward = &toForward.items,
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/view/history_view_group_call_bar.h" // GenerateUserpics...
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -1492,27 +1492,14 @@ object_ptr<Ui::BoxContent> ShareInviteLinkBox(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto error = [&] {
|
||||
for (const auto thread : result) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
thread,
|
||||
{ .text = &comment });
|
||||
if (!error.isEmpty()) {
|
||||
return std::make_pair(error, thread);
|
||||
}
|
||||
}
|
||||
return std::make_pair(QString(), result.front());
|
||||
}();
|
||||
if (!error.first.isEmpty()) {
|
||||
auto text = TextWithEntities();
|
||||
if (result.size() > 1) {
|
||||
text.append(
|
||||
Ui::Text::Bold(error.second->chatListName())
|
||||
).append("\n\n");
|
||||
}
|
||||
text.append(error.first);
|
||||
const auto errorWithThread = GetErrorForSending(
|
||||
result,
|
||||
{ .text = &comment });
|
||||
if (errorWithThread.error) {
|
||||
if (*box) {
|
||||
(*box)->uiShow()->showBox(Ui::MakeInformBox(text));
|
||||
(*box)->uiShow()->showBox(MakeSendErrorBox(
|
||||
errorWithThread,
|
||||
result.size() > 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ SendFilesCheck DefaultCheckForPeer(
|
|||
}
|
||||
|
||||
SendFilesCheck DefaultCheckForPeer(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer) {
|
||||
return [=](
|
||||
const Ui::PreparedFile &file,
|
||||
|
@ -228,7 +228,7 @@ SendFilesCheck DefaultCheckForPeer(
|
|||
bool silent) {
|
||||
const auto error = Data::FileRestrictionError(peer, file, compress);
|
||||
if (error && !silent) {
|
||||
show->showToast(*error);
|
||||
Data::ShowSendErrorToast(show, peer, error);
|
||||
}
|
||||
return !error.has_value();
|
||||
};
|
||||
|
|
|
@ -80,7 +80,7 @@ using SendFilesCheck = Fn<bool(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] SendFilesCheck DefaultCheckForPeer(
|
||||
std::shared_ptr<Ui::Show> show,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
using SendFilesConfirmed = Fn<void(
|
||||
|
|
|
@ -1508,26 +1508,11 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto error = [&] {
|
||||
for (const auto thread : result) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
thread,
|
||||
{ .forward = &items, .text = &comment });
|
||||
if (!error.isEmpty()) {
|
||||
return std::make_pair(error, thread);
|
||||
}
|
||||
}
|
||||
return std::make_pair(QString(), result.front());
|
||||
}();
|
||||
if (!error.first.isEmpty()) {
|
||||
auto text = TextWithEntities();
|
||||
if (result.size() > 1) {
|
||||
text.append(
|
||||
Ui::Text::Bold(error.second->chatListName())
|
||||
).append("\n\n");
|
||||
}
|
||||
text.append(error.first);
|
||||
show->showBox(Ui::MakeInformBox(text));
|
||||
const auto error = GetErrorForSending(
|
||||
result,
|
||||
{ .forward = &items, .text = &comment });
|
||||
if (error.error) {
|
||||
show->showBox(MakeSendErrorBox(error, result.size() > 1));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1737,30 +1722,13 @@ void FastShareLink(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto error = [&] {
|
||||
for (const auto thread : result) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
thread,
|
||||
{ .text = &comment });
|
||||
if (!error.isEmpty()) {
|
||||
return std::make_pair(error, thread);
|
||||
}
|
||||
}
|
||||
return std::make_pair(QString(), result.front());
|
||||
}();
|
||||
if (!error.first.isEmpty()) {
|
||||
auto text = TextWithEntities();
|
||||
if (result.size() > 1) {
|
||||
text.append(
|
||||
Ui::Text::Bold(error.second->chatListName())
|
||||
).append("\n\n");
|
||||
}
|
||||
text.append(error.first);
|
||||
const auto error = GetErrorForSending(
|
||||
result,
|
||||
{ .text = &comment });
|
||||
if (error.error) {
|
||||
if (const auto weak = *box) {
|
||||
weak->getDelegate()->show(Ui::MakeConfirmBox({
|
||||
.text = text,
|
||||
.inform = true,
|
||||
}));
|
||||
weak->getDelegate()->show(
|
||||
MakeSendErrorBox(error, result.size() > 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "boxes/share_box.h"
|
||||
#include "history/view/history_view_schedule_box.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/history.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -139,30 +139,13 @@ object_ptr<ShareBox> ShareInviteLinkBox(
|
|||
return;
|
||||
}
|
||||
|
||||
const auto error = [&] {
|
||||
for (const auto thread : result) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
thread,
|
||||
{ .text = &comment });
|
||||
if (!error.isEmpty()) {
|
||||
return std::make_pair(error, thread);
|
||||
}
|
||||
}
|
||||
return std::make_pair(QString(), result.front());
|
||||
}();
|
||||
if (!error.first.isEmpty()) {
|
||||
auto text = TextWithEntities();
|
||||
if (result.size() > 1) {
|
||||
text.append(
|
||||
Ui::Text::Bold(error.second->chatListName())
|
||||
).append("\n\n");
|
||||
}
|
||||
text.append(error.first);
|
||||
const auto error = GetErrorForSending(
|
||||
result,
|
||||
{ .text = &comment });
|
||||
if (error.error) {
|
||||
if (const auto weak = *box) {
|
||||
weak->getDelegate()->show(ConfirmBox({
|
||||
.text = text,
|
||||
.inform = true,
|
||||
}));
|
||||
weak->getDelegate()->show(
|
||||
MakeSendErrorBox(error, result.size() > 1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "chat_helpers/gifs_list_widget.h"
|
||||
#include "menu/menu_send.h"
|
||||
#include "ui/controls/tabbed_search.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
|
@ -1042,23 +1043,39 @@ void TabbedSelector::checkRestrictedPeer() {
|
|||
? Data::RestrictionError(
|
||||
_currentPeer,
|
||||
ChatRestriction::SendOther)
|
||||
: std::nullopt)
|
||||
: std::nullopt;
|
||||
if (error) {
|
||||
if (!_restrictedLabel) {
|
||||
_restrictedLabel.create(
|
||||
this,
|
||||
*error,
|
||||
st::stickersRestrictedLabel);
|
||||
_restrictedLabel->show();
|
||||
updateRestrictedLabelGeometry();
|
||||
currentTab()->footer()->hide();
|
||||
_scroll->hide();
|
||||
_bottomShadow->hide();
|
||||
update();
|
||||
}
|
||||
: Data::SendError())
|
||||
: Data::SendError();
|
||||
const auto changed = (_restrictedLabelKey != error.text);
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
_restrictedLabelKey = error.text;
|
||||
if (error) {
|
||||
const auto show = _show;
|
||||
const auto peer = _currentPeer;
|
||||
_restrictedLabel.create(
|
||||
this,
|
||||
rpl::single(error.boostsToLift
|
||||
? Ui::Text::Link(error.text)
|
||||
: TextWithEntities{ error.text }),
|
||||
st::stickersRestrictedLabel);
|
||||
const auto lifting = error.boostsToLift;
|
||||
_restrictedLabel->setClickHandlerFilter([=](auto...) {
|
||||
const auto window = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo);
|
||||
window->resolveBoostState(peer->asChannel(), lifting);
|
||||
return false;
|
||||
});
|
||||
_restrictedLabel->show();
|
||||
updateRestrictedLabelGeometry();
|
||||
currentTab()->footer()->hide();
|
||||
_scroll->hide();
|
||||
_bottomShadow->hide();
|
||||
update();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_restrictedLabelKey = QString();
|
||||
}
|
||||
if (_restrictedLabel) {
|
||||
_restrictedLabel.destroy();
|
||||
|
|
|
@ -309,6 +309,7 @@ private:
|
|||
object_ptr<Ui::PlainShadow> _bottomShadow;
|
||||
object_ptr<Ui::ScrollArea> _scroll;
|
||||
object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
|
||||
QString _restrictedLabelKey;
|
||||
std::vector<Tab> _tabs;
|
||||
SelectorTab _currentTabType = SelectorTab::Emoji;
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "base/unixtime.h"
|
||||
#include "boxes/peers/edit_peer_permissions_box.h"
|
||||
#include "chat_helpers/compose/compose_show.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
|
@ -17,6 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/chat/attach/attach_prepare.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -167,7 +171,7 @@ bool CanSendAnyOf(
|
|||
Unexpected("Peer type in CanSendAnyOf.");
|
||||
}
|
||||
|
||||
std::optional<QString> RestrictionError(
|
||||
SendError RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction) {
|
||||
using Flag = ChatRestriction;
|
||||
|
@ -175,10 +179,13 @@ std::optional<QString> RestrictionError(
|
|||
if (const auto user = peer->asUser()) {
|
||||
if (user->meRequiresPremiumToWrite()
|
||||
&& !user->session().premium()) {
|
||||
return tr::lng_restricted_send_non_premium(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->shortName());
|
||||
return SendError({
|
||||
.text = tr::lng_restricted_send_non_premium(
|
||||
tr::now,
|
||||
lt_user,
|
||||
user->shortName()),
|
||||
.premiumToLift = true,
|
||||
});
|
||||
}
|
||||
const auto result = (restriction == Flag::SendVoiceMessages)
|
||||
? tr::lng_restricted_send_voice_messages(
|
||||
|
@ -194,7 +201,7 @@ std::optional<QString> RestrictionError(
|
|||
? u"can't send polls :("_q
|
||||
: (restriction == Flag::PinMessages)
|
||||
? u"can't pin :("_q
|
||||
: std::optional<QString>();
|
||||
: SendError();
|
||||
|
||||
Ensures(result.has_value());
|
||||
return result;
|
||||
|
@ -253,6 +260,15 @@ std::optional<QString> RestrictionError(
|
|||
Unexpected("Restriction in Data::RestrictionErrorKey.");
|
||||
}
|
||||
}
|
||||
if (all
|
||||
&& channel->boostsUnrestrict()
|
||||
&& !channel->unrestrictedByBoosts()) {
|
||||
return SendError({
|
||||
.text = tr::lng_restricted_boost_group(tr::now),
|
||||
.boostsToLift = (channel->boostsUnrestrict()
|
||||
- channel->boostsApplied()),
|
||||
});
|
||||
}
|
||||
switch (restriction) {
|
||||
case Flag::SendPolls:
|
||||
return all
|
||||
|
@ -302,10 +318,10 @@ std::optional<QString> RestrictionError(
|
|||
}
|
||||
Unexpected("Restriction in Data::RestrictionErrorKey.");
|
||||
}
|
||||
return std::nullopt;
|
||||
return SendError();
|
||||
}
|
||||
|
||||
std::optional<QString> AnyFileRestrictionError(not_null<PeerData*> peer) {
|
||||
SendError AnyFileRestrictionError(not_null<PeerData*> peer) {
|
||||
using Restriction = ChatRestriction;
|
||||
for (const auto right : FilesSendRestrictionsList()) {
|
||||
if (!RestrictionError(peer, right)) {
|
||||
|
@ -315,7 +331,7 @@ std::optional<QString> AnyFileRestrictionError(not_null<PeerData*> peer) {
|
|||
return RestrictionError(peer, Restriction::SendFiles);
|
||||
}
|
||||
|
||||
std::optional<QString> FileRestrictionError(
|
||||
SendError FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) {
|
||||
|
@ -339,7 +355,7 @@ std::optional<QString> FileRestrictionError(
|
|||
return {};
|
||||
}
|
||||
|
||||
std::optional<QString> FileRestrictionError(
|
||||
SendError FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedFile &file,
|
||||
std::optional<bool> compress) {
|
||||
|
@ -383,4 +399,32 @@ std::optional<QString> FileRestrictionError(
|
|||
return {};
|
||||
}
|
||||
|
||||
void ShowSendErrorToast(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer,
|
||||
Data::SendError error) {
|
||||
return ShowSendErrorToast(navigation->uiShow(), peer, error);
|
||||
}
|
||||
|
||||
void ShowSendErrorToast(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
Data::SendError error) {
|
||||
Expects(peer->isChannel());
|
||||
|
||||
if (!error.boostsToLift) {
|
||||
show->showToast(*error);
|
||||
return;
|
||||
}
|
||||
const auto boost = [=] {
|
||||
const auto window = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo);
|
||||
window->resolveBoostState(peer->asChannel(), error.boostsToLift);
|
||||
};
|
||||
show->showToast({
|
||||
.text = Ui::Text::Link(*error),
|
||||
.filter = [=](const auto &...) { boost(); return false; },
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -7,11 +7,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
namespace ChatHelpers {
|
||||
class Show;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Ui {
|
||||
struct PreparedList;
|
||||
struct PreparedFile;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Window {
|
||||
class SessionNavigation;
|
||||
} // namespace Window
|
||||
|
||||
enum class ChatAdminRight {
|
||||
ChangeInfo = (1 << 0),
|
||||
PostMessages = (1 << 1),
|
||||
|
@ -175,18 +183,65 @@ struct RestrictionsSetOptions {
|
|||
return CanSendAnyOf(peer, AllSendRestrictions(), forbidInForums);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<QString> RestrictionError(
|
||||
struct SendError {
|
||||
SendError(QString text = QString()) : text(std::move(text)) {
|
||||
}
|
||||
|
||||
struct Args {
|
||||
QString text;
|
||||
int boostsToLift = 0;
|
||||
bool premiumToLift = false;
|
||||
};
|
||||
SendError(Args &&args)
|
||||
: text(std::move(args.text))
|
||||
, boostsToLift(args.boostsToLift)
|
||||
, premiumToLift(args.premiumToLift) {
|
||||
}
|
||||
|
||||
QString text;
|
||||
int boostsToLift = 0;
|
||||
bool premiumToLift = false;
|
||||
|
||||
[[nodiscard]] SendError value_or(SendError other) const {
|
||||
return *this ? *this : other;
|
||||
}
|
||||
|
||||
explicit operator bool() const {
|
||||
return !text.isEmpty();
|
||||
}
|
||||
[[nodiscard]] bool has_value() const {
|
||||
return !text.isEmpty();
|
||||
}
|
||||
[[nodiscard]] const QString &operator*() const {
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
struct SendErrorWithThread {
|
||||
SendError error;
|
||||
Thread *thread = nullptr;
|
||||
};
|
||||
|
||||
[[nodiscard]] SendError RestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
ChatRestriction restriction);
|
||||
[[nodiscard]] std::optional<QString> AnyFileRestrictionError(
|
||||
not_null<PeerData*> peer);
|
||||
[[nodiscard]] std::optional<QString> FileRestrictionError(
|
||||
[[nodiscard]] SendError AnyFileRestrictionError(not_null<PeerData*> peer);
|
||||
[[nodiscard]] SendError FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress);
|
||||
[[nodiscard]] std::optional<QString> FileRestrictionError(
|
||||
[[nodiscard]] SendError FileRestrictionError(
|
||||
not_null<PeerData*> peer,
|
||||
const Ui::PreparedFile &file,
|
||||
std::optional<bool> compress);
|
||||
|
||||
void ShowSendErrorToast(
|
||||
not_null<Window::SessionNavigation*> navigation,
|
||||
not_null<PeerData*> peer,
|
||||
SendError error);
|
||||
void ShowSendErrorToast(
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
not_null<PeerData*> peer,
|
||||
SendError error);
|
||||
|
||||
} // namespace Data
|
||||
|
|
|
@ -423,7 +423,7 @@ bool Story::hasDirectLink() const {
|
|||
return !_peer->username().isEmpty();
|
||||
}
|
||||
|
||||
std::optional<QString> Story::errorTextForForward(
|
||||
Data::SendError Story::errorTextForForward(
|
||||
not_null<Thread*> to) const {
|
||||
const auto peer = to->peer();
|
||||
const auto holdsPhoto = v::is<not_null<PhotoData*>>(_media.data);
|
||||
|
@ -433,10 +433,10 @@ std::optional<QString> Story::errorTextForForward(
|
|||
const auto second = holdsPhoto
|
||||
? ChatRestriction::SendVideos
|
||||
: ChatRestriction::SendPhotos;
|
||||
if (const auto error = Data::RestrictionError(peer, first)) {
|
||||
return *error;
|
||||
} else if (const auto error = Data::RestrictionError(peer, second)) {
|
||||
return *error;
|
||||
if (const auto one = Data::RestrictionError(peer, first)) {
|
||||
return one;
|
||||
} else if (const auto two = Data::RestrictionError(peer, second)) {
|
||||
return two;
|
||||
} else if (!Data::CanSend(to, first, false)
|
||||
|| !Data::CanSend(to, second, false)) {
|
||||
return tr::lng_forward_cant(tr::now);
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Data {
|
|||
class Session;
|
||||
class Thread;
|
||||
class MediaPreload;
|
||||
struct SendError;
|
||||
|
||||
enum class StoryPrivacy : uchar {
|
||||
Public,
|
||||
|
@ -191,7 +192,7 @@ public:
|
|||
[[nodiscard]] bool canReport() const;
|
||||
|
||||
[[nodiscard]] bool hasDirectLink() const;
|
||||
[[nodiscard]] std::optional<QString> errorTextForForward(
|
||||
[[nodiscard]] Data::SendError errorTextForForward(
|
||||
not_null<Thread*> to) const;
|
||||
|
||||
void setCaption(TextWithEntities &&caption);
|
||||
|
|
|
@ -2479,17 +2479,17 @@ bool HistoryItem::requiresSendInlineRight() const {
|
|||
return Has<HistoryMessageVia>();
|
||||
}
|
||||
|
||||
std::optional<QString> HistoryItem::errorTextForForward(
|
||||
Data::SendError 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;
|
||||
return error;
|
||||
} else if (requiresInline && !Data::CanSend(to, kInline)) {
|
||||
return Data::RestrictionError(peer, kInline).value_or(
|
||||
tr::lng_forward_cant(tr::now));
|
||||
const auto forInline = Data::RestrictionError(peer, kInline);
|
||||
return forInline ? forInline : tr::lng_forward_cant(tr::now);
|
||||
} else if (_media
|
||||
&& _media->poll()
|
||||
&& _media->poll()->publicVotes()
|
||||
|
|
|
@ -68,6 +68,7 @@ struct SponsoredFrom;
|
|||
class Story;
|
||||
class SavedSublist;
|
||||
struct PaidReactionSend;
|
||||
struct SendError;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
|
@ -442,7 +443,7 @@ public:
|
|||
[[nodiscard]] bool suggestDeleteAllReport() const;
|
||||
[[nodiscard]] ChatRestriction requiredSendRight() const;
|
||||
[[nodiscard]] bool requiresSendInlineRight() const;
|
||||
[[nodiscard]] std::optional<QString> errorTextForForward(
|
||||
[[nodiscard]] Data::SendError errorTextForForward(
|
||||
not_null<Data::Thread*> to) const;
|
||||
[[nodiscard]] const HistoryMessageTranslation *translation() const;
|
||||
[[nodiscard]] bool translationShowRequiresCheck(LanguageId to) const;
|
||||
|
|
|
@ -38,6 +38,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/unixtime.h"
|
||||
#include "core/application.h"
|
||||
#include "core/click_handler_types.h" // ClickHandlerContext.
|
||||
#include "ui/boxes/confirm_box.h"
|
||||
#include "ui/text/format_values.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/toast/toast.h"
|
||||
|
@ -59,7 +60,7 @@ bool PeerCallKnown(not_null<PeerData*> peer) {
|
|||
|
||||
} // namespace
|
||||
|
||||
QString GetErrorTextForSending(
|
||||
Data::SendError GetErrorForSending(
|
||||
not_null<PeerData*> peer,
|
||||
SendingErrorRequest request) {
|
||||
const auto forum = request.topicRootId ? peer->forum() : nullptr;
|
||||
|
@ -71,13 +72,13 @@ QString GetErrorTextForSending(
|
|||
: peer->owner().history(peer);
|
||||
if (request.story) {
|
||||
if (const auto error = request.story->errorTextForForward(thread)) {
|
||||
return *error;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
if (request.forward) {
|
||||
for (const auto &item : *request.forward) {
|
||||
if (const auto error = item->errorTextForForward(thread)) {
|
||||
return *error;
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +88,7 @@ QString GetErrorTextForSending(
|
|||
peer,
|
||||
ChatRestriction::SendOther);
|
||||
if (error) {
|
||||
return *error;
|
||||
return error;
|
||||
} else if (!Data::CanSendTexts(thread)) {
|
||||
return tr::lng_forward_cant(tr::now);
|
||||
}
|
||||
|
@ -134,14 +135,58 @@ QString GetErrorTextForSending(
|
|||
}
|
||||
}
|
||||
|
||||
return QString();
|
||||
return {};
|
||||
}
|
||||
|
||||
QString GetErrorTextForSending(
|
||||
Data::SendError GetErrorForSending(
|
||||
not_null<Data::Thread*> thread,
|
||||
SendingErrorRequest request) {
|
||||
request.topicRootId = thread->topicRootId();
|
||||
return GetErrorTextForSending(thread->peer(), std::move(request));
|
||||
return GetErrorForSending(thread->peer(), std::move(request));
|
||||
}
|
||||
|
||||
Data::SendErrorWithThread GetErrorForSending(
|
||||
const std::vector<not_null<Data::Thread*>> &threads,
|
||||
SendingErrorRequest request) {
|
||||
for (const auto thread : threads) {
|
||||
const auto error = GetErrorForSending(thread, request);
|
||||
if (error) {
|
||||
return Data::SendErrorWithThread{ error, thread };
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
object_ptr<Ui::BoxContent> MakeSendErrorBox(
|
||||
const Data::SendErrorWithThread &error,
|
||||
bool withTitle) {
|
||||
Expects(error.error.has_value() && error.thread != nullptr);
|
||||
|
||||
auto text = TextWithEntities();
|
||||
if (withTitle) {
|
||||
text.append(
|
||||
Ui::Text::Bold(error.thread->chatListName())
|
||||
).append("\n\n");
|
||||
}
|
||||
if (error.error.boostsToLift) {
|
||||
text.append(Ui::Text::Link(error.error.text));
|
||||
} else {
|
||||
text.append(error.error.text);
|
||||
}
|
||||
const auto peer = error.thread->peer();
|
||||
const auto lifting = error.error.boostsToLift;
|
||||
const auto filter = [=](const auto &...) {
|
||||
Expects(peer->isChannel());
|
||||
|
||||
const auto window = ChatHelpers::ResolveWindowDefault()(
|
||||
&peer->session(),
|
||||
ChatHelpers::WindowUsage::PremiumPromo);
|
||||
window->resolveBoostState(peer->asChannel(), lifting);
|
||||
return false;
|
||||
};
|
||||
return Ui::MakeInformBox({
|
||||
.text = text,
|
||||
.labelFilter = filter,
|
||||
});
|
||||
}
|
||||
|
||||
void RequestDependentMessageItem(
|
||||
|
|
|
@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/object_ptr.h"
|
||||
|
||||
class History;
|
||||
|
||||
namespace Api {
|
||||
|
@ -17,12 +19,18 @@ struct SendAction;
|
|||
namespace Data {
|
||||
class Story;
|
||||
class Thread;
|
||||
struct SendError;
|
||||
struct SendErrorWithThread;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class BoxContent;
|
||||
} // namespace Ui
|
||||
|
||||
struct PreparedServiceText {
|
||||
TextWithEntities text;
|
||||
std::vector<ClickHandlerPtr> links;
|
||||
|
@ -108,13 +116,20 @@ struct SendingErrorRequest {
|
|||
const TextWithTags *text = nullptr;
|
||||
bool ignoreSlowmodeCountdown = false;
|
||||
};
|
||||
[[nodiscard]] QString GetErrorTextForSending(
|
||||
[[nodiscard]] Data::SendError GetErrorForSending(
|
||||
not_null<PeerData*> peer,
|
||||
SendingErrorRequest request);
|
||||
[[nodiscard]] QString GetErrorTextForSending(
|
||||
[[nodiscard]] Data::SendError GetErrorForSending(
|
||||
not_null<Data::Thread*> thread,
|
||||
SendingErrorRequest request);
|
||||
|
||||
[[nodiscard]] Data::SendErrorWithThread GetErrorForSending(
|
||||
const std::vector<not_null<Data::Thread*>> &threads,
|
||||
SendingErrorRequest request);
|
||||
[[nodiscard]] object_ptr<Ui::BoxContent> MakeSendErrorBox(
|
||||
const Data::SendErrorWithThread &error,
|
||||
bool withTitle);
|
||||
|
||||
[[nodiscard]] TextWithEntities DropDisallowedCustomEmoji(
|
||||
not_null<PeerData*> to,
|
||||
TextWithEntities text);
|
||||
|
|
|
@ -85,7 +85,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_inner_widget.h"
|
||||
#include "history/history_item_components.h"
|
||||
|
@ -1028,7 +1028,7 @@ void HistoryWidget::refreshTabbedPanel() {
|
|||
|
||||
void HistoryWidget::initVoiceRecordBar() {
|
||||
_voiceRecordBar->setStartRecordingFilter([=] {
|
||||
const auto error = [&]() -> std::optional<QString> {
|
||||
const auto error = [&]() -> Data::SendError {
|
||||
if (_peer) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
_peer,
|
||||
|
@ -1036,10 +1036,10 @@ void HistoryWidget::initVoiceRecordBar() {
|
|||
return error;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}();
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return true;
|
||||
} else if (showSlowmodeError()) {
|
||||
return true;
|
||||
|
@ -4672,7 +4672,7 @@ void HistoryWidget::chooseAttach(
|
|||
if (!_peer || !_canSendMessages) {
|
||||
return;
|
||||
} else if (const auto error = Data::AnyFileRestrictionError(_peer)) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return;
|
||||
} else if (showSlowmodeError()) {
|
||||
return;
|
||||
|
@ -5702,12 +5702,12 @@ bool HistoryWidget::showSendingFilesError(
|
|||
bool HistoryWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto error = [&]() -> Data::SendError {
|
||||
const auto error = _peer
|
||||
? Data::FileRestrictionError(_peer, list, compress)
|
||||
: std::nullopt;
|
||||
if (error) {
|
||||
return *error;
|
||||
: Data::SendError();
|
||||
if (!_peer || error) {
|
||||
return error;
|
||||
} else if (const auto left = _peer->slowmodeSecondsLeft()) {
|
||||
return tr::lng_slowmode_enabled(
|
||||
tr::now,
|
||||
|
@ -5727,15 +5727,15 @@ bool HistoryWidget::showSendingFilesError(
|
|||
}
|
||||
return tr::lng_forward_send_files_cant(tr::now);
|
||||
}();
|
||||
if (text.isEmpty()) {
|
||||
if (!error) {
|
||||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
} else if (error.text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
controller()->show(
|
||||
Box(FileSizeLimitBox, &session(), fileSize, nullptr));
|
||||
return true;
|
||||
}
|
||||
controller()->showToast(text);
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5775,7 +5775,7 @@ bool HistoryWidget::showSendMessageError(
|
|||
return false;
|
||||
}
|
||||
const auto topicRootId = resolveReplyToTopicRootId();
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
_peer,
|
||||
{
|
||||
.topicRootId = topicRootId,
|
||||
|
@ -5783,10 +5783,10 @@ bool HistoryWidget::showSendMessageError(
|
|||
.text = &textWithTags,
|
||||
.ignoreSlowmodeCountdown = ignoreSlowmodeCountdown,
|
||||
});
|
||||
if (error.isEmpty()) {
|
||||
if (!error) {
|
||||
return false;
|
||||
}
|
||||
controller()->showToast(error);
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6286,39 +6286,39 @@ int HistoryWidget::countAutomaticScrollTop() {
|
|||
return ScrollMax;
|
||||
}
|
||||
|
||||
QString HistoryWidget::computeSendRestriction() const {
|
||||
if (const auto user = _peer ? _peer->asUser() : nullptr) {
|
||||
if (user->meRequiresPremiumToWrite()
|
||||
&& !user->session().premium()) {
|
||||
return u"premium_required"_q;
|
||||
}
|
||||
}
|
||||
Data::SendError HistoryWidget::computeSendRestriction() const {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto error = (_peer && !Data::CanSendAnyOf(_peer, allWithoutPolls))
|
||||
return (_peer && !Data::CanSendAnyOf(_peer, allWithoutPolls))
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendOther)
|
||||
: std::nullopt;
|
||||
return error ? (u"restriction:"_q + *error) : QString();
|
||||
: Data::SendError();
|
||||
}
|
||||
|
||||
void HistoryWidget::updateSendRestriction() {
|
||||
const auto restriction = computeSendRestriction();
|
||||
if (_sendRestrictionKey == restriction) {
|
||||
if (_sendRestrictionKey == restriction.text) {
|
||||
return;
|
||||
}
|
||||
_sendRestrictionKey = restriction;
|
||||
if (restriction.isEmpty()) {
|
||||
_sendRestrictionKey = restriction.text;
|
||||
if (!restriction) {
|
||||
_sendRestriction = nullptr;
|
||||
} else if (restriction == u"premium_required"_q) {
|
||||
} else if (restriction.premiumToLift) {
|
||||
_sendRestriction = PremiumRequiredSendRestriction(
|
||||
this,
|
||||
_peer->asUser(),
|
||||
controller());
|
||||
} else if (restriction.startsWith(u"restriction:"_q)) {
|
||||
const auto error = restriction.mid(12);
|
||||
_sendRestriction = TextErrorSendRestriction(this, error);
|
||||
} else if (const auto lifting = restriction.boostsToLift) {
|
||||
auto button = base::make_unique_q<Ui::FlatButton>(
|
||||
this,
|
||||
restriction.text,
|
||||
st::historyComposeButton);
|
||||
const auto channel = _peer->asChannel();
|
||||
button->setClickedCallback([=] {
|
||||
controller()->resolveBoostState(channel, lifting);
|
||||
});
|
||||
_sendRestriction = std::move(button);
|
||||
} else {
|
||||
Unexpected("Restriction type.");
|
||||
_sendRestriction = TextErrorSendRestriction(this, restriction.text);
|
||||
}
|
||||
if (_sendRestriction) {
|
||||
_sendRestriction->show();
|
||||
|
@ -7130,9 +7130,8 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto errorText = result.result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
controller()->showToast(errorText);
|
||||
if (const auto error = result.result->getErrorOnSend(_history)) {
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7774,9 +7773,9 @@ bool HistoryWidget::sendExistingDocument(
|
|||
std::optional<MsgId> localId) {
|
||||
const auto error = _peer
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendStickers)
|
||||
: std::nullopt;
|
||||
: Data::SendError();
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return false;
|
||||
} else if (!_peer
|
||||
|| !_canSendMessages
|
||||
|
@ -7811,9 +7810,9 @@ bool HistoryWidget::sendExistingPhoto(
|
|||
Api::SendOptions options) {
|
||||
const auto error = _peer
|
||||
? Data::RestrictionError(_peer, ChatRestriction::SendPhotos)
|
||||
: std::nullopt;
|
||||
: Data::SendError();
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _peer, error);
|
||||
return false;
|
||||
} else if (!_peer || !_canSendMessages) {
|
||||
return false;
|
||||
|
|
|
@ -29,6 +29,7 @@ class Error;
|
|||
|
||||
namespace Data {
|
||||
class PhotoMedia;
|
||||
struct SendError;
|
||||
} // namespace Data
|
||||
|
||||
namespace SendMenu {
|
||||
|
@ -579,7 +580,7 @@ private:
|
|||
void addMessagesToBack(not_null<PeerData*> peer, const QVector<MTPMessage> &messages);
|
||||
|
||||
void updateSendRestriction();
|
||||
[[nodiscard]] QString computeSendRestriction() const;
|
||||
[[nodiscard]] Data::SendError computeSendRestriction() const;
|
||||
void updateHistoryGeometry(bool initial = false, bool loadedDown = false, const ScrollChange &change = { ScrollChangeNone, 0 });
|
||||
void updateListSize();
|
||||
void startItemRevealAnimations();
|
||||
|
|
|
@ -48,6 +48,7 @@ struct WriteRestriction {
|
|||
QString text;
|
||||
QString button;
|
||||
Type type = Type::None;
|
||||
int boostsToLift = false;
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return (type == Type::None);
|
||||
|
|
|
@ -2222,7 +2222,7 @@ void SetupRestrictionView(
|
|||
not_null<Ui::RpWidget*> widget,
|
||||
not_null<const style::ComposeControls*> st,
|
||||
std::shared_ptr<ChatHelpers::Show> show,
|
||||
const QString &name,
|
||||
not_null<PeerData*> peer,
|
||||
rpl::producer<Controls::WriteRestriction> restriction,
|
||||
Fn<void(QPainter &p, QRect clip)> paintBackground) {
|
||||
struct State {
|
||||
|
@ -2234,7 +2234,9 @@ void SetupRestrictionView(
|
|||
};
|
||||
const auto state = widget->lifetime().make_state<State>();
|
||||
state->updateGeometries = [=] {
|
||||
if (!state->label) {
|
||||
if (!state->label && state->button) {
|
||||
state->button->setGeometry(widget->rect());
|
||||
} else if (!state->label) {
|
||||
return;
|
||||
} else if (state->button) {
|
||||
const auto available = widget->width()
|
||||
|
@ -2307,14 +2309,24 @@ void SetupRestrictionView(
|
|||
) | rpl::distinct_until_changed(
|
||||
) | rpl::start_with_next([=](Controls::WriteRestriction value) {
|
||||
using Type = Controls::WriteRestriction::Type;
|
||||
if (value.type == Type::Rights) {
|
||||
if (const auto lifting = value.boostsToLift) {
|
||||
state->button = std::make_unique<Ui::FlatButton>(
|
||||
widget,
|
||||
tr::lng_restricted_boost_group(tr::now),
|
||||
st::historyComposeButton);
|
||||
state->button->setClickedCallback([=] {
|
||||
const auto window = show->resolveWindow(
|
||||
ChatHelpers::WindowUsage::PremiumPromo);
|
||||
window->resolveBoostState(peer->asChannel(), lifting);
|
||||
});
|
||||
} else if (value.type == Type::Rights) {
|
||||
state->icon = nullptr;
|
||||
state->unlock = nullptr;
|
||||
state->button = nullptr;
|
||||
state->label = makeLabel(value.text, st->restrictionLabel);
|
||||
} else if (value.type == Type::PremiumRequired) {
|
||||
state->icon = makeIcon();
|
||||
state->unlock = makeUnlock(value.button, name);
|
||||
state->unlock = makeUnlock(value.button, peer->shortName());
|
||||
state->button = std::make_unique<Ui::AbstractButton>(widget);
|
||||
state->button->setClickedCallback([=] {
|
||||
::Settings::ShowPremiumPromoToast(
|
||||
|
@ -2322,7 +2334,7 @@ void SetupRestrictionView(
|
|||
tr::lng_send_non_premium_message_toast(
|
||||
tr::now,
|
||||
lt_user,
|
||||
TextWithEntities{ name },
|
||||
TextWithEntities{ peer->shortName() },
|
||||
lt_link,
|
||||
Ui::Text::Link(
|
||||
Ui::Text::Bold(
|
||||
|
@ -2373,7 +2385,7 @@ void ComposeControls::initWriteRestriction() {
|
|||
_writeRestricted.get(),
|
||||
&_st,
|
||||
_show,
|
||||
_history->peer->shortName(),
|
||||
_history->peer,
|
||||
_writeRestriction.value(),
|
||||
background);
|
||||
|
||||
|
@ -2405,7 +2417,7 @@ void ComposeControls::initVoiceRecordBar() {
|
|||
}, _wrap->lifetime());
|
||||
|
||||
_voiceRecordBar->setStartRecordingFilter([=] {
|
||||
const auto error = [&]() -> std::optional<QString> {
|
||||
const auto error = [&]() -> Data::SendError {
|
||||
const auto peer = _history ? _history->peer.get() : nullptr;
|
||||
if (peer) {
|
||||
if (const auto error = Data::RestrictionError(
|
||||
|
@ -2414,10 +2426,10 @@ void ComposeControls::initVoiceRecordBar() {
|
|||
return error;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
return {};
|
||||
}();
|
||||
if (error) {
|
||||
_show->showToast(*error);
|
||||
Data::ShowSendErrorToast(_show, _history->peer, error);
|
||||
return true;
|
||||
} else if (_showSlowmodeError && _showSlowmodeError()) {
|
||||
return true;
|
||||
|
|
|
@ -23,7 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item_components.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/history_view_swipe.h"
|
||||
#include "ui/chat/pinned_bar.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
|
@ -661,7 +661,7 @@ void RepliesWidget::setupComposeControls() {
|
|||
? _topic
|
||||
: _history->peer->forumTopicFor(_rootId);
|
||||
return (!topic || topic->canToggleClosed() || !topic->closed())
|
||||
? std::optional<QString>()
|
||||
? Data::SendError()
|
||||
: tr::lng_forum_topic_closed(tr::now);
|
||||
});
|
||||
auto writeRestriction = rpl::combine(
|
||||
|
@ -670,7 +670,7 @@ void RepliesWidget::setupComposeControls() {
|
|||
Data::PeerUpdate::Flag::Rights),
|
||||
Data::CanSendAnythingValue(_history->peer),
|
||||
std::move(topicWriteRestrictions)
|
||||
) | rpl::map([=](auto, auto, std::optional<QString> topicRestriction) {
|
||||
) | rpl::map([=](auto, auto, Data::SendError topicRestriction) {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto canSendAnything = _topic
|
||||
|
@ -687,10 +687,11 @@ void RepliesWidget::setupComposeControls() {
|
|||
: tr::lng_group_not_accessible(tr::now))
|
||||
: topicRestriction
|
||||
? std::move(topicRestriction)
|
||||
: std::optional<QString>();
|
||||
: Data::SendError();
|
||||
return text ? Controls::WriteRestriction{
|
||||
.text = std::move(*text),
|
||||
.type = Controls::WriteRestrictionType::Rights,
|
||||
.boostsToLift = text.boostsToLift,
|
||||
} : Controls::WriteRestriction();
|
||||
});
|
||||
|
||||
|
@ -936,7 +937,7 @@ void RepliesWidget::chooseAttach(
|
|||
std::optional<bool> overrideSendImagesAsPhotos) {
|
||||
_choosingAttach = false;
|
||||
if (const auto error = Data::AnyFileRestrictionError(_history->peer)) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return;
|
||||
} else if (showSlowmodeError()) {
|
||||
return;
|
||||
|
@ -1168,11 +1169,11 @@ bool RepliesWidget::showSendingFilesError(
|
|||
bool RepliesWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto error = [&]() -> Data::SendError {
|
||||
const auto peer = _history->peer;
|
||||
const auto error = Data::FileRestrictionError(peer, list, compress);
|
||||
if (error) {
|
||||
return *error;
|
||||
return error;
|
||||
} else if (const auto left = _history->peer->slowmodeSecondsLeft()) {
|
||||
return tr::lng_slowmode_enabled(
|
||||
tr::now,
|
||||
|
@ -1192,16 +1193,16 @@ bool RepliesWidget::showSendingFilesError(
|
|||
}
|
||||
return tr::lng_forward_send_files_cant(tr::now);
|
||||
}();
|
||||
if (text.isEmpty()) {
|
||||
if (!error) {
|
||||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
} else if (error.text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
controller()->show(
|
||||
Box(FileSizeLimitBox, &session(), fileSize, nullptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
controller()->showToast(text);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1247,7 +1248,7 @@ void RepliesWidget::send(Api::SendOptions options) {
|
|||
message.textWithTags = _composeControls->getTextWithAppliedMarkdown();
|
||||
message.webPage = _composeControls->webPageDraft();
|
||||
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
_history->peer,
|
||||
{
|
||||
.topicRootId = _topic ? _topic->rootId() : MsgId(0),
|
||||
|
@ -1255,8 +1256,8 @@ void RepliesWidget::send(Api::SendOptions options) {
|
|||
.text = &message.textWithTags,
|
||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
controller()->showToast(error);
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1407,7 +1408,7 @@ bool RepliesWidget::sendExistingDocument(
|
|||
_history->peer,
|
||||
ChatRestriction::SendStickers);
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return false;
|
||||
} else if (showSlowmodeError()
|
||||
|| ShowSendPremiumError(controller(), document)) {
|
||||
|
@ -1435,7 +1436,7 @@ bool RepliesWidget::sendExistingPhoto(
|
|||
_history->peer,
|
||||
ChatRestriction::SendPhotos);
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return false;
|
||||
} else if (showSlowmodeError()) {
|
||||
return false;
|
||||
|
@ -1453,9 +1454,8 @@ bool RepliesWidget::sendExistingPhoto(
|
|||
void RepliesWidget::sendInlineResult(
|
||||
not_null<InlineBots::Result*> result,
|
||||
not_null<UserData*> bot) {
|
||||
const auto errorText = result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
controller()->showToast(errorText);
|
||||
if (const auto error = result->getErrorOnSend(_history)) {
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return;
|
||||
}
|
||||
sendInlineResult(result, bot, {}, std::nullopt);
|
||||
|
|
|
@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_sticker_toast.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_drag_area.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "menu/menu_send.h" // SendMenu::Type.
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/tooltip.h"
|
||||
|
@ -252,83 +252,85 @@ ScheduledWidget::~ScheduledWidget() = default;
|
|||
void ScheduledWidget::setupComposeControls() {
|
||||
auto writeRestriction = _forumTopic
|
||||
? [&] {
|
||||
auto topicWriteRestrictions = rpl::single(
|
||||
) | rpl::then(session().changes().topicUpdates(
|
||||
Data::TopicUpdate::Flag::Closed
|
||||
) | rpl::filter([=](const Data::TopicUpdate &update) {
|
||||
return (update.topic->history() == _history)
|
||||
&& (update.topic->rootId() == _forumTopic->rootId());
|
||||
}) | rpl::to_empty) | rpl::map([=] {
|
||||
return (!_forumTopic
|
||||
|| _forumTopic->canToggleClosed()
|
||||
|| !_forumTopic->closed())
|
||||
? std::optional<QString>()
|
||||
: tr::lng_forum_topic_closed(tr::now);
|
||||
});
|
||||
return rpl::combine(
|
||||
session().changes().peerFlagsValue(
|
||||
_history->peer,
|
||||
Data::PeerUpdate::Flag::Rights),
|
||||
Data::CanSendAnythingValue(_history->peer),
|
||||
std::move(topicWriteRestrictions)
|
||||
) | rpl::map([=](
|
||||
auto,
|
||||
auto,
|
||||
std::optional<QString> topicRestriction) {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto canSendAnything = Data::CanSendAnyOf(
|
||||
_forumTopic,
|
||||
allWithoutPolls);
|
||||
const auto restriction = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendOther);
|
||||
auto text = !canSendAnything
|
||||
? (restriction
|
||||
? restriction
|
||||
auto topicWriteRestrictions = rpl::single(
|
||||
) | rpl::then(session().changes().topicUpdates(
|
||||
Data::TopicUpdate::Flag::Closed
|
||||
) | rpl::filter([=](const Data::TopicUpdate &update) {
|
||||
return (update.topic->history() == _history)
|
||||
&& (update.topic->rootId() == _forumTopic->rootId());
|
||||
}) | rpl::to_empty) | rpl::map([=] {
|
||||
return (!_forumTopic
|
||||
|| _forumTopic->canToggleClosed()
|
||||
|| !_forumTopic->closed())
|
||||
? Data::SendError()
|
||||
: tr::lng_forum_topic_closed(tr::now);
|
||||
});
|
||||
return rpl::combine(
|
||||
session().changes().peerFlagsValue(
|
||||
_history->peer,
|
||||
Data::PeerUpdate::Flag::Rights),
|
||||
Data::CanSendAnythingValue(_history->peer),
|
||||
std::move(topicWriteRestrictions)
|
||||
) | rpl::map([=](
|
||||
auto,
|
||||
auto,
|
||||
Data::SendError topicRestriction) {
|
||||
const auto allWithoutPolls = Data::AllSendRestrictions()
|
||||
& ~ChatRestriction::SendPolls;
|
||||
const auto canSendAnything = Data::CanSendAnyOf(
|
||||
_forumTopic,
|
||||
allWithoutPolls);
|
||||
const auto restriction = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendOther);
|
||||
auto text = !canSendAnything
|
||||
? (restriction
|
||||
? restriction
|
||||
: topicRestriction
|
||||
? std::move(topicRestriction)
|
||||
: tr::lng_group_not_accessible(tr::now))
|
||||
: topicRestriction
|
||||
? std::move(topicRestriction)
|
||||
: tr::lng_group_not_accessible(tr::now))
|
||||
: topicRestriction
|
||||
? std::move(topicRestriction)
|
||||
: std::optional<QString>();
|
||||
return text ? Controls::WriteRestriction{
|
||||
.text = std::move(*text),
|
||||
.type = Controls::WriteRestrictionType::Rights,
|
||||
} : Controls::WriteRestriction();
|
||||
}) | rpl::type_erased();
|
||||
}()
|
||||
: Data::SendError();
|
||||
return text ? Controls::WriteRestriction{
|
||||
.text = std::move(*text),
|
||||
.type = Controls::WriteRestrictionType::Rights,
|
||||
.boostsToLift = text.boostsToLift,
|
||||
} : Controls::WriteRestriction();
|
||||
}) | rpl::type_erased();
|
||||
}()
|
||||
: [&] {
|
||||
return 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,
|
||||
false);
|
||||
const auto restriction = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendOther);
|
||||
auto text = !canSendAnything
|
||||
? (restriction
|
||||
? restriction
|
||||
: tr::lng_group_not_accessible(tr::now))
|
||||
: std::optional<QString>();
|
||||
return text ? Controls::WriteRestriction{
|
||||
.text = std::move(*text),
|
||||
.type = Controls::WriteRestrictionType::Rights,
|
||||
} : Controls::WriteRestriction();
|
||||
}) | rpl::type_erased();
|
||||
}();
|
||||
return 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,
|
||||
false);
|
||||
const auto restriction = Data::RestrictionError(
|
||||
_history->peer,
|
||||
ChatRestriction::SendOther);
|
||||
auto text = !canSendAnything
|
||||
? (restriction
|
||||
? restriction
|
||||
: tr::lng_group_not_accessible(tr::now))
|
||||
: Data::SendError();
|
||||
return text ? Controls::WriteRestriction{
|
||||
.text = std::move(*text),
|
||||
.type = Controls::WriteRestrictionType::Rights,
|
||||
.boostsToLift = text.boostsToLift,
|
||||
} : Controls::WriteRestriction();
|
||||
}) | rpl::type_erased();
|
||||
}();
|
||||
_composeControls->setHistory({
|
||||
.history = _history.get(),
|
||||
.writeRestriction = std::move(writeRestriction),
|
||||
});
|
||||
});
|
||||
|
||||
_composeControls->height(
|
||||
) | rpl::start_with_next([=] {
|
||||
|
@ -463,7 +465,7 @@ void ScheduledWidget::setupComposeControls() {
|
|||
|
||||
void ScheduledWidget::chooseAttach() {
|
||||
if (const auto error = Data::AnyFileRestrictionError(_history->peer)) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -667,12 +669,12 @@ bool ScheduledWidget::showSendingFilesError(
|
|||
bool ScheduledWidget::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto error = [&]() -> Data::SendError {
|
||||
using Error = Ui::PreparedList::Error;
|
||||
const auto peer = _history->peer;
|
||||
const auto error = Data::FileRestrictionError(peer, list, compress);
|
||||
if (error) {
|
||||
return *error;
|
||||
return error;
|
||||
} else switch (list.error) {
|
||||
case Error::None: return QString();
|
||||
case Error::EmptyFile:
|
||||
|
@ -685,16 +687,16 @@ bool ScheduledWidget::showSendingFilesError(
|
|||
}
|
||||
return tr::lng_forward_send_files_cant(tr::now);
|
||||
}();
|
||||
if (text.isEmpty()) {
|
||||
if (!error) {
|
||||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
} else if (error.text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
controller()->show(
|
||||
Box(FileSizeLimitBox, &session(), fileSize, nullptr));
|
||||
return true;
|
||||
}
|
||||
|
||||
controller()->showToast(text);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -717,7 +719,7 @@ void ScheduledWidget::send() {
|
|||
return;
|
||||
}
|
||||
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
_history->peer,
|
||||
{
|
||||
.topicRootId = _forumTopic
|
||||
|
@ -729,8 +731,8 @@ void ScheduledWidget::send() {
|
|||
.text = &textWithTags,
|
||||
.ignoreSlowmodeCountdown = true,
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
controller()->showToast(error);
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Api::SendOptions options) { send(options); };
|
||||
|
@ -865,7 +867,7 @@ bool ScheduledWidget::sendExistingDocument(
|
|||
_history->peer,
|
||||
ChatRestriction::SendStickers);
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return false;
|
||||
} else if (ShowSendPremiumError(controller(), document)) {
|
||||
return false;
|
||||
|
@ -893,7 +895,7 @@ bool ScheduledWidget::sendExistingPhoto(
|
|||
_history->peer,
|
||||
ChatRestriction::SendPhotos);
|
||||
if (error) {
|
||||
controller()->showToast(*error);
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -909,9 +911,8 @@ bool ScheduledWidget::sendExistingPhoto(
|
|||
void ScheduledWidget::sendInlineResult(
|
||||
not_null<InlineBots::Result*> result,
|
||||
not_null<UserData*> bot) {
|
||||
const auto errorText = result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
controller()->showToast(errorText);
|
||||
if (const auto error = result->getErrorOnSend(_history)) {
|
||||
Data::ShowSendErrorToast(controller(), _history->peer, error);
|
||||
return;
|
||||
}
|
||||
const auto callback = [=](Api::SendOptions options) {
|
||||
|
|
|
@ -394,13 +394,9 @@ not_null<HistoryItem*> Result::makeMessage(
|
|||
return sendData->makeMessage(this, history, std::move(fields));
|
||||
}
|
||||
|
||||
QString Result::getErrorOnSend(not_null<History*> history) const {
|
||||
const auto specific = sendData->getErrorOnSend(this, history);
|
||||
return !specific.isEmpty()
|
||||
? specific
|
||||
: Data::RestrictionError(
|
||||
history->peer,
|
||||
ChatRestriction::SendInline).value_or(QString());
|
||||
Data::SendError Result::getErrorOnSend(not_null<History*> history) const {
|
||||
return sendData->getErrorOnSend(this, history).value_or(
|
||||
Data::RestrictionError(history->peer, ChatRestriction::SendInline));
|
||||
}
|
||||
|
||||
std::optional<Data::LocationPoint> Result::getLocationPoint() const {
|
||||
|
|
|
@ -20,6 +20,7 @@ struct HistoryItemCommonFields;
|
|||
|
||||
namespace Data {
|
||||
class LocationPoint;
|
||||
struct SendError;
|
||||
} // namespace Data
|
||||
|
||||
namespace InlineBots {
|
||||
|
@ -69,7 +70,8 @@ public:
|
|||
[[nodiscard]] not_null<HistoryItem*> makeMessage(
|
||||
not_null<History*> history,
|
||||
HistoryItemCommonFields &&fields) const;
|
||||
QString getErrorOnSend(not_null<History*> history) const;
|
||||
[[nodiscard]] Data::SendError getErrorOnSend(
|
||||
not_null<History*> history) const;
|
||||
|
||||
// interface for Layout:: usage
|
||||
std::optional<Data::LocationPoint> getLocationPoint() const;
|
||||
|
|
|
@ -42,11 +42,11 @@ not_null<HistoryItem*> SendDataCommon::makeMessage(
|
|||
std::move(distinct.media));
|
||||
}
|
||||
|
||||
QString SendDataCommon::getErrorOnSend(
|
||||
Data::SendError SendDataCommon::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto type = ChatRestriction::SendOther;
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
return Data::RestrictionError(history->peer, type);
|
||||
}
|
||||
|
||||
SendDataCommon::SentMessageFields SendText::getSentMessageFields() const {
|
||||
|
@ -106,11 +106,11 @@ not_null<HistoryItem*> SendPhoto::makeMessage(
|
|||
TextWithEntities{ _message, _entities });
|
||||
}
|
||||
|
||||
QString SendPhoto::getErrorOnSend(
|
||||
Data::SendError SendPhoto::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto type = ChatRestriction::SendPhotos;
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
return Data::RestrictionError(history->peer, type);
|
||||
}
|
||||
|
||||
not_null<HistoryItem*> SendFile::makeMessage(
|
||||
|
@ -123,11 +123,11 @@ not_null<HistoryItem*> SendFile::makeMessage(
|
|||
TextWithEntities{ _message, _entities });
|
||||
}
|
||||
|
||||
QString SendFile::getErrorOnSend(
|
||||
Data::SendError SendFile::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto type = _document->requiredSendRight();
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
return Data::RestrictionError(history->peer, type);
|
||||
}
|
||||
|
||||
not_null<HistoryItem*> SendGame::makeMessage(
|
||||
|
@ -137,11 +137,11 @@ not_null<HistoryItem*> SendGame::makeMessage(
|
|||
return history->makeMessage(std::move(fields), _game);
|
||||
}
|
||||
|
||||
QString SendGame::getErrorOnSend(
|
||||
Data::SendError SendGame::getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const {
|
||||
const auto type = ChatRestriction::SendGames;
|
||||
return Data::RestrictionError(history->peer, type).value_or(QString());
|
||||
return Data::RestrictionError(history->peer, type);
|
||||
}
|
||||
|
||||
SendDataCommon::SentMessageFields SendInvoice::getSentMessageFields() const {
|
||||
|
|
|
@ -11,6 +11,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
struct HistoryItemCommonFields;
|
||||
|
||||
namespace Data {
|
||||
struct SendError;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
@ -44,7 +48,7 @@ public:
|
|||
const Result *owner,
|
||||
not_null<History*> history,
|
||||
HistoryItemCommonFields &&fields) const = 0;
|
||||
virtual QString getErrorOnSend(
|
||||
virtual Data::SendError getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const = 0;
|
||||
|
||||
|
@ -80,7 +84,7 @@ public:
|
|||
not_null<History*> history,
|
||||
HistoryItemCommonFields &&fields) const override;
|
||||
|
||||
QString getErrorOnSend(
|
||||
Data::SendError getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const override;
|
||||
|
||||
|
@ -241,7 +245,7 @@ public:
|
|||
not_null<History*> history,
|
||||
HistoryItemCommonFields &&fields) const override;
|
||||
|
||||
QString getErrorOnSend(
|
||||
Data::SendError getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const override;
|
||||
|
||||
|
@ -275,7 +279,7 @@ public:
|
|||
not_null<History*> history,
|
||||
HistoryItemCommonFields &&fields) const override;
|
||||
|
||||
QString getErrorOnSend(
|
||||
Data::SendError getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const override;
|
||||
|
||||
|
@ -303,7 +307,7 @@ public:
|
|||
not_null<History*> history,
|
||||
HistoryItemCommonFields &&fields) const override;
|
||||
|
||||
QString getErrorOnSend(
|
||||
Data::SendError getErrorOnSend(
|
||||
const Result *owner,
|
||||
not_null<History*> history) const override;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mainwindow.h"
|
||||
#include "main/main_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "ui/text/text_utilities.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
|
@ -113,19 +114,35 @@ void Inner::checkRestrictedPeer() {
|
|||
const auto error = Data::RestrictionError(
|
||||
_inlineQueryPeer,
|
||||
ChatRestriction::SendInline);
|
||||
if (error) {
|
||||
if (!_restrictedLabel) {
|
||||
_restrictedLabel.create(this, *error, st::stickersRestrictedLabel);
|
||||
_restrictedLabel->show();
|
||||
_restrictedLabel->move(st::inlineResultsLeft - st::roundRadiusSmall, st::stickerPanPadding);
|
||||
_restrictedLabel->resizeToNaturalWidth(width() - (st::inlineResultsLeft - st::roundRadiusSmall) * 2);
|
||||
if (_switchPmButton) {
|
||||
_switchPmButton->hide();
|
||||
}
|
||||
repaintItems();
|
||||
}
|
||||
const auto changed = (_restrictedLabelKey != error.text);
|
||||
if (!changed) {
|
||||
return;
|
||||
}
|
||||
_restrictedLabelKey = error.text;
|
||||
if (error) {
|
||||
const auto window = _controller;
|
||||
const auto peer = _inlineQueryPeer;
|
||||
_restrictedLabel.create(
|
||||
this,
|
||||
rpl::single(error.boostsToLift
|
||||
? Ui::Text::Link(error.text)
|
||||
: TextWithEntities{ error.text }),
|
||||
st::stickersRestrictedLabel);
|
||||
const auto lifting = error.boostsToLift;
|
||||
_restrictedLabel->setClickHandlerFilter([=](auto...) {
|
||||
window->resolveBoostState(peer->asChannel(), lifting);
|
||||
return false;
|
||||
});
|
||||
_restrictedLabel->show();
|
||||
updateRestrictedLabelGeometry();
|
||||
if (_switchPmButton) {
|
||||
_switchPmButton->hide();
|
||||
}
|
||||
repaintItems();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
_restrictedLabelKey = QString();
|
||||
}
|
||||
if (_restrictedLabel) {
|
||||
_restrictedLabel.destroy();
|
||||
|
@ -136,6 +153,18 @@ void Inner::checkRestrictedPeer() {
|
|||
}
|
||||
}
|
||||
|
||||
void Inner::updateRestrictedLabelGeometry() {
|
||||
if (!_restrictedLabel) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto labelWidth = width() - st::stickerPanPadding * 2;
|
||||
_restrictedLabel->resizeToWidth(labelWidth);
|
||||
_restrictedLabel->moveToLeft(
|
||||
(width() - _restrictedLabel->width()) / 2,
|
||||
st::stickerPanPadding);
|
||||
}
|
||||
|
||||
bool Inner::isRestrictedView() {
|
||||
checkRestrictedPeer();
|
||||
return (_restrictedLabel != nullptr);
|
||||
|
@ -178,6 +207,10 @@ rpl::producer<> Inner::inlineRowsCleared() const {
|
|||
|
||||
Inner::~Inner() = default;
|
||||
|
||||
void Inner::resizeEvent(QResizeEvent *e) {
|
||||
updateRestrictedLabelGeometry();
|
||||
}
|
||||
|
||||
void Inner::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
QRect r = e ? e->rect() : rect();
|
||||
|
|
|
@ -108,6 +108,7 @@ protected:
|
|||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void leaveEventHook(QEvent *e) override;
|
||||
void leaveToChildEvent(QEvent *e, QWidget *child) override;
|
||||
|
@ -136,6 +137,7 @@ private:
|
|||
void clearInlineRows(bool resultsDeleted);
|
||||
ItemBase *layoutPrepareInlineResult(Result *result);
|
||||
|
||||
void updateRestrictedLabelGeometry();
|
||||
void deleteUnusedInlineLayouts();
|
||||
|
||||
int validateExistingInlineRows(const Results &results);
|
||||
|
@ -162,6 +164,7 @@ private:
|
|||
QByteArray _switchPmUrl;
|
||||
|
||||
object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
|
||||
QString _restrictedLabelKey;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "dialogs/dialogs_widget.h"
|
||||
#include "history/history_widget.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/view/media/history_view_media.h"
|
||||
#include "history/view/history_view_service_message.h"
|
||||
#include "history/view/history_view_sublist_section.h"
|
||||
|
@ -556,15 +556,15 @@ bool MainWidget::setForwardDraft(
|
|||
const auto history = thread->owningHistory();
|
||||
const auto items = session().data().idsToItems(draft.ids);
|
||||
const auto topicRootId = thread->topicRootId();
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
history->peer,
|
||||
{
|
||||
.topicRootId = topicRootId,
|
||||
.forward = &items,
|
||||
.ignoreSlowmodeCountdown = true,
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
_controller->show(Ui::MakeInformBox(error));
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(_controller, history->peer, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -611,12 +611,12 @@ bool MainWidget::sendPaths(
|
|||
not_null<Data::Thread*> thread,
|
||||
const QStringList &paths) {
|
||||
if (!Data::CanSendAnyOf(thread, Data::FilesSendRestrictions())) {
|
||||
_controller->show(Ui::MakeInformBox(
|
||||
tr::lng_forward_send_files_cant()));
|
||||
_controller->showToast(
|
||||
tr::lng_forward_send_files_cant(tr::now));
|
||||
return false;
|
||||
} else if (const auto error = Data::AnyFileRestrictionError(
|
||||
thread->peer())) {
|
||||
_controller->show(Ui::MakeInformBox(*error));
|
||||
Data::ShowSendErrorToast(controller(), thread->peer(), error);
|
||||
return false;
|
||||
} else {
|
||||
_controller->showThread(
|
||||
|
@ -659,12 +659,12 @@ bool MainWidget::filesOrForwardDrop(
|
|||
}
|
||||
return false;
|
||||
} else if (!Data::CanSendAnyOf(thread, Data::FilesSendRestrictions())) {
|
||||
_controller->show(Ui::MakeInformBox(
|
||||
tr::lng_forward_send_files_cant()));
|
||||
_controller->showToast(
|
||||
tr::lng_forward_send_files_cant(tr::now));
|
||||
return false;
|
||||
} else if (const auto error = Data::AnyFileRestrictionError(
|
||||
thread->peer())) {
|
||||
_controller->show(Ui::MakeInformBox(*error));
|
||||
Data::ShowSendErrorToast(_controller, thread->peer(), error);
|
||||
return false;
|
||||
} else {
|
||||
_controller->showThread(
|
||||
|
|
|
@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "core/file_utilities.h"
|
||||
#include "core/mime_type.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "data/data_chat_participant_status.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_message_reaction_id.h"
|
||||
#include "data/data_peer_values.h"
|
||||
|
@ -219,15 +220,15 @@ bool ReplyArea::send(
|
|||
return false;
|
||||
}
|
||||
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
_data.peer,
|
||||
{
|
||||
.topicRootId = MsgId(0),
|
||||
.text = &message.textWithTags,
|
||||
.ignoreSlowmodeCountdown = (options.scheduled != 0),
|
||||
});
|
||||
if (!error.isEmpty()) {
|
||||
_controller->uiShow()->showToast(error);
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(_controller->uiShow(), _data.peer, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -262,7 +263,7 @@ bool ReplyArea::sendExistingDocument(
|
|||
_data.peer,
|
||||
ChatRestriction::SendStickers);
|
||||
if (error) {
|
||||
show->showToast(*error);
|
||||
Data::ShowSendErrorToast(show, _data.peer, error);
|
||||
return false;
|
||||
} else if (showSlowmodeError()
|
||||
|| Window::ShowSendPremiumError(show, document)) {
|
||||
|
@ -290,7 +291,7 @@ bool ReplyArea::sendExistingPhoto(
|
|||
_data.peer,
|
||||
ChatRestriction::SendPhotos);
|
||||
if (error) {
|
||||
show->showToast(*error);
|
||||
Data::ShowSendErrorToast(show, _data.peer, error);
|
||||
return false;
|
||||
} else if (showSlowmodeError()) {
|
||||
return false;
|
||||
|
@ -308,9 +309,9 @@ bool ReplyArea::sendExistingPhoto(
|
|||
void ReplyArea::sendInlineResult(
|
||||
not_null<InlineBots::Result*> result,
|
||||
not_null<UserData*> bot) {
|
||||
const auto errorText = result->getErrorOnSend(history());
|
||||
if (!errorText.isEmpty()) {
|
||||
_controller->uiShow()->showToast(errorText);
|
||||
if (const auto error = result->getErrorOnSend(history())) {
|
||||
const auto show = _controller->uiShow();
|
||||
Data::ShowSendErrorToast(show, history()->peer, error);
|
||||
return;
|
||||
}
|
||||
sendInlineResult(result, bot, {}, std::nullopt);
|
||||
|
@ -363,11 +364,11 @@ bool ReplyArea::showSendingFilesError(
|
|||
bool ReplyArea::showSendingFilesError(
|
||||
const Ui::PreparedList &list,
|
||||
std::optional<bool> compress) const {
|
||||
const auto text = [&] {
|
||||
const auto error = [&]() -> Data::SendError {
|
||||
const auto peer = _data.peer;
|
||||
const auto error = Data::FileRestrictionError(peer, list, compress);
|
||||
if (error) {
|
||||
return *error;
|
||||
return error;
|
||||
}
|
||||
using Error = Ui::PreparedList::Error;
|
||||
switch (list.error) {
|
||||
|
@ -382,9 +383,9 @@ bool ReplyArea::showSendingFilesError(
|
|||
}
|
||||
return tr::lng_forward_send_files_cant(tr::now);
|
||||
}();
|
||||
if (text.isEmpty()) {
|
||||
if (!error) {
|
||||
return false;
|
||||
} else if (text == u"(toolarge)"_q) {
|
||||
} else if (error.text == u"(toolarge)"_q) {
|
||||
const auto fileSize = list.files.back().size;
|
||||
_controller->uiShow()->showBox(Box(
|
||||
FileSizeLimitBox,
|
||||
|
@ -394,7 +395,7 @@ bool ReplyArea::showSendingFilesError(
|
|||
return true;
|
||||
}
|
||||
|
||||
_controller->uiShow()->showToast(text);
|
||||
Data::ShowSendErrorToast(_controller->uiShow(), _data.peer, error);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -422,7 +423,7 @@ void ReplyArea::chooseAttach(
|
|||
}
|
||||
const auto peer = not_null(_data.peer);
|
||||
if (const auto error = Data::AnyFileRestrictionError(peer)) {
|
||||
_controller->uiShow()->showToast(*error);
|
||||
Data::ShowSendErrorToast(_controller->uiShow(), peer, error);
|
||||
return;
|
||||
} else if (showSlowmodeError()) {
|
||||
return;
|
||||
|
|
|
@ -22,7 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_thread.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/view/history_view_context_menu.h" // CopyStoryLink.
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
|
@ -87,26 +87,11 @@ namespace Media::Stories {
|
|||
return;
|
||||
}
|
||||
const auto peer = story->peer();
|
||||
const auto error = [&] {
|
||||
for (const auto thread : result) {
|
||||
const auto error = GetErrorTextForSending(
|
||||
thread,
|
||||
{ .story = story, .text = &comment });
|
||||
if (!error.isEmpty()) {
|
||||
return std::make_pair(error, thread);
|
||||
}
|
||||
}
|
||||
return std::make_pair(QString(), result.front());
|
||||
}();
|
||||
if (!error.first.isEmpty()) {
|
||||
auto text = TextWithEntities();
|
||||
if (result.size() > 1) {
|
||||
text.append(
|
||||
Ui::Text::Bold(error.second->chatListName())
|
||||
).append("\n\n");
|
||||
}
|
||||
text.append(error.first);
|
||||
show->showBox(Ui::MakeInformBox(text));
|
||||
const auto error = GetErrorForSending(
|
||||
result,
|
||||
{ .story = story, .text = &comment });
|
||||
if (error.error) {
|
||||
show->showBox(MakeSendErrorBox(error, result.size() > 1));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -185,7 +185,9 @@ std::optional<QString> RestrictionToSend(
|
|||
not_null<Window::Controller*> controller,
|
||||
ChatRestriction right) {
|
||||
if (const auto peer = ActiveChat(controller).peer()) {
|
||||
return Data::RestrictionError(peer, right);
|
||||
if (const auto error = Data::RestrictionError(peer, right)) {
|
||||
return *error;
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
|
|
@ -1538,10 +1538,8 @@ void ShortcutMessages::sendInlineResult(
|
|||
not_null<UserData*> bot) {
|
||||
if (showPremiumRequired()) {
|
||||
return;
|
||||
}
|
||||
const auto errorText = result->getErrorOnSend(_history);
|
||||
if (!errorText.isEmpty()) {
|
||||
_controller->showToast(errorText);
|
||||
} else if (const auto error = result->getErrorOnSend(_history)) {
|
||||
Data::ShowSendErrorToast(_controller, _history->peer, error);
|
||||
return;
|
||||
}
|
||||
sendInlineResult(result, bot, {}, std::nullopt);
|
||||
|
|
|
@ -325,8 +325,14 @@ void BoostBox(
|
|||
return (counters.mine > 1) ? u"x%1"_q.arg(counters.mine) : u""_q;
|
||||
});
|
||||
|
||||
const auto wasMine = state->data.current().mine;
|
||||
const auto wasLifting = data.lifting;
|
||||
auto text = state->data.value(
|
||||
) | rpl::map([=](BoostCounters counters) {
|
||||
const auto lifting = wasLifting
|
||||
? (wasLifting
|
||||
- std::clamp(counters.mine - wasMine, 0, wasLifting - 1))
|
||||
: 0;
|
||||
const auto bold = Ui::Text::Bold(name);
|
||||
const auto now = counters.boosts;
|
||||
const auto full = !counters.nextLevelBoosts;
|
||||
|
@ -337,7 +343,14 @@ void BoostBox(
|
|||
lt_count,
|
||||
rpl::single(float64(counters.level + (left ? 1 : 0))),
|
||||
Ui::Text::RichLangValue);
|
||||
return (counters.mine || full)
|
||||
return (lifting > 1)
|
||||
? tr::lng_boost_group_lift_restrictions_many(
|
||||
lt_count,
|
||||
rpl::single(float64(lifting)),
|
||||
Ui::Text::RichLangValue)
|
||||
: lifting
|
||||
? tr::lng_boost_group_lift_restrictions(Ui::Text::RichLangValue)
|
||||
: (counters.mine || full)
|
||||
? (left
|
||||
? tr::lng_boost_channel_needs_unlock(
|
||||
lt_count,
|
||||
|
@ -365,6 +378,14 @@ void BoostBox(
|
|||
rpl::single(bold),
|
||||
Ui::Text::RichLangValue);
|
||||
}) | rpl::flatten_latest();
|
||||
if (wasLifting) {
|
||||
state->data.value(
|
||||
) | rpl::start_with_next([=](BoostCounters counters) {
|
||||
if (counters.mine - wasMine >= wasLifting) {
|
||||
box->closeBox();
|
||||
}
|
||||
}, box->lifetime());
|
||||
}
|
||||
|
||||
auto faded = object_ptr<Ui::FadeWrap<>>(
|
||||
close->parentWidget(),
|
||||
|
|
|
@ -48,6 +48,7 @@ struct BoostBoxData {
|
|||
QString name;
|
||||
BoostCounters boost;
|
||||
BoostFeatures features;
|
||||
int lifting = 0;
|
||||
bool allowMulti = false;
|
||||
bool group = false;
|
||||
};
|
||||
|
|
|
@ -61,7 +61,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "api/api_updates.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item_helpers.h" // GetErrorTextForSending.
|
||||
#include "history/history_item_helpers.h" // GetErrorForSending.
|
||||
#include "history/view/history_view_context_menu.h"
|
||||
#include "window/window_separate_id.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -2595,11 +2595,11 @@ QPointer<Ui::BoxContent> ShowSendNowMessagesBox(
|
|||
: tr::lng_scheduled_send_now(tr::now);
|
||||
|
||||
const auto list = session->data().idsToItems(items);
|
||||
const auto error = GetErrorTextForSending(
|
||||
const auto error = GetErrorForSending(
|
||||
history->peer,
|
||||
{ .forward = &list });
|
||||
if (!error.isEmpty()) {
|
||||
navigation->showToast(error);
|
||||
if (error) {
|
||||
Data::ShowSendErrorToast(navigation, history->peer, error);
|
||||
return { nullptr };
|
||||
}
|
||||
auto done = [
|
||||
|
|
|
@ -764,7 +764,10 @@ void SessionNavigation::showPeerByLinkResolved(
|
|||
}
|
||||
}
|
||||
|
||||
void SessionNavigation::resolveBoostState(not_null<ChannelData*> channel) {
|
||||
void SessionNavigation::resolveBoostState(
|
||||
not_null<ChannelData*> channel,
|
||||
int boostsToLift) {
|
||||
_boostsToLift = boostsToLift;
|
||||
if (_boostStateResolving == channel) {
|
||||
return;
|
||||
}
|
||||
|
@ -772,18 +775,33 @@ void SessionNavigation::resolveBoostState(not_null<ChannelData*> channel) {
|
|||
_api.request(MTPpremium_GetBoostsStatus(
|
||||
channel->input
|
||||
)).done([=](const MTPpremium_BoostsStatus &result) {
|
||||
_boostStateResolving = nullptr;
|
||||
if (base::take(_boostStateResolving) != channel) {
|
||||
return;
|
||||
}
|
||||
const auto boosted = std::make_shared<bool>();
|
||||
channel->updateLevelHint(result.data().vlevel().v);
|
||||
const auto submit = [=](Fn<void(Ui::BoostCounters)> done) {
|
||||
applyBoost(channel, done);
|
||||
applyBoost(channel, [=](Ui::BoostCounters counters) {
|
||||
*boosted = true;
|
||||
done(counters);
|
||||
});
|
||||
};
|
||||
uiShow()->show(Box(Ui::BoostBox, Ui::BoostBoxData{
|
||||
const auto lifting = base::take(_boostsToLift);
|
||||
const auto box = uiShow()->show(Box(Ui::BoostBox, Ui::BoostBoxData{
|
||||
.name = channel->name(),
|
||||
.boost = ParseBoostCounters(result),
|
||||
.features = LookupBoostFeatures(channel),
|
||||
.lifting = lifting,
|
||||
.allowMulti = (BoostsForGift(_session) > 0),
|
||||
.group = channel->isMegagroup(),
|
||||
}, submit));
|
||||
if (lifting) {
|
||||
box->boxClosing() | rpl::start_with_next([=] {
|
||||
if (*boosted) {
|
||||
channel->updateFullForced();
|
||||
}
|
||||
}, box->lifetime());
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
_boostStateResolving = nullptr;
|
||||
showToast(u"Error: "_q + error.type());
|
||||
|
|
|
@ -253,7 +253,9 @@ public:
|
|||
Dialogs::Key inChat,
|
||||
PeerData *searchFrom = nullptr);
|
||||
|
||||
void resolveBoostState(not_null<ChannelData*> channel);
|
||||
void resolveBoostState(
|
||||
not_null<ChannelData*> channel,
|
||||
int boostsToLift = 0);
|
||||
|
||||
void resolveCollectible(
|
||||
PeerId ownerId,
|
||||
|
@ -319,6 +321,7 @@ private:
|
|||
mtpRequestId _showingRepliesRequestId = 0;
|
||||
|
||||
ChannelData *_boostStateResolving = nullptr;
|
||||
int _boostsToLift = 0;
|
||||
|
||||
QString _collectibleEntity;
|
||||
mtpRequestId _collectibleRequestId = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue