Block field with toast if texts are not allowed.

This commit is contained in:
John Preston 2023-01-31 21:21:47 +04:00
parent d697a57834
commit 2886ae6909
7 changed files with 191 additions and 32 deletions

View file

@ -1944,6 +1944,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_broadcast_ph" = "Broadcast a message...";
"lng_broadcast_silent_ph" = "Silent broadcast...";
"lng_send_anonymous_ph" = "Send anonymously...";
"lng_send_text_no" = "Text not allowed.";
"lng_send_text_no_about" = "The admins of this group only allow sending {types}.";
"lng_send_text_type_and_last" = "{types} and {last}";
"lng_send_text_type_photos" = "Photos";
"lng_send_text_type_videos" = "Video files";
"lng_send_text_type_video_messages" = "Video Messages";
"lng_send_text_type_music" = "Music";
"lng_send_text_type_voice_messages" = "Voice Messages";
"lng_send_text_type_files" = "Files";
"lng_send_text_type_stickers" = "Stickers & GIFs";
"lng_send_text_type_polls" = "Polls";
"lng_send_as_title" = "Send message as...";
"lng_send_as_anonymous_admin" = "Anonymous admin";
"lng_send_as_premium_required" = "Subscribe to {link} to be able to comment on behalf of your channels in group chats.";

View file

@ -18,7 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/shortcuts.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "ui/toast/toast.h"
#include "ui/wrap/vertical_layout.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/popup_menu.h"
#include "ui/ui_utility.h"
#include "data/data_session.h"
@ -50,6 +52,7 @@ using EditLinkAction = Ui::InputField::EditLinkAction;
using EditLinkSelection = Ui::InputField::EditLinkSelection;
constexpr auto kParseLinksTimeout = crl::time(1000);
constexpr auto kTypesDuration = 4 * crl::time(1000);
// For mention / custom emoji tags save and validate selfId,
// ignore tags for different users.
@ -773,3 +776,86 @@ void MessageLinksParser::apply(
}
_list = std::move(parsed);
}
base::unique_qptr<Ui::RpWidget> CreateDisabledFieldView(
QWidget *parent,
not_null<PeerData*> peer) {
auto result = base::make_unique_q<Ui::AbstractButton>(parent);
const auto raw = result.get();
const auto label = CreateChild<Ui::FlatLabel>(
result.get(),
tr::lng_send_text_no(),
st::historySendDisabled);
label->setAttribute(Qt::WA_TransparentForMouseEvents);
raw->setPointerCursor(false);
raw->widthValue(
) | rpl::start_with_next([=](int width) {
const auto &st = st::historyComposeField;
const auto margins = (st.textMargins + st.placeholderMargins);
const auto available = width - margins.left() - margins.right();
const auto skip = st::historySendDisabledIconSkip;
label->resizeToWidth(available - skip);
label->moveToLeft(margins.left() + skip, margins.top(), width);
}, label->lifetime());
raw->paintRequest(
) | rpl::start_with_next([=] {
auto p = QPainter(raw);
const auto &st = st::historyComposeField;
const auto margins = (st.textMargins + st.placeholderMargins);
const auto &icon = st::historySendDisabledIcon;
icon.paint(
p,
margins.left() + st::historySendDisabledPosition.x(),
margins.top() + st::historySendDisabledPosition.y(),
raw->width());
}, raw->lifetime());
using WeakToast = base::weak_ptr<Ui::Toast::Instance>;
const auto toast = raw->lifetime().make_state<WeakToast>();
raw->setClickedCallback([=] {
if (toast->get()) {
return;
}
using Flag = ChatRestriction;
const auto map = base::flat_map<Flag, tr::phrase<>>{
{ Flag::SendPhotos, tr::lng_send_text_type_photos },
{ Flag::SendVideos, tr::lng_send_text_type_videos },
{
Flag::SendVideoMessages,
tr::lng_send_text_type_video_messages,
},
{ Flag::SendMusic, tr::lng_send_text_type_music },
{
Flag::SendVoiceMessages,
tr::lng_send_text_type_voice_messages,
},
{ Flag::SendFiles, tr::lng_send_text_type_files },
{ Flag::SendStickers, tr::lng_send_text_type_stickers },
{ Flag::SendPolls, tr::lng_send_text_type_polls },
};
auto list = QStringList();
for (const auto &[flag, phrase] : map) {
if (Data::CanSend(peer, flag, false)) {
list.append(phrase(tr::now));
}
}
if (list.empty()) {
return;
}
const auto types = (list.size() > 1)
? tr::lng_send_text_type_and_last(
tr::now,
lt_types,
list.mid(0, list.size() - 1).join(", "),
lt_last,
list.back())
: list.back();
*toast = Ui::Toast::Show(parent, {
.text = { tr::lng_send_text_no_about(tr::now, lt_types, types) },
.st = &st::defaultMultilineToast,
.durationMs = kTypesDuration,
.multiline = true,
.slideSide = RectPart::Bottom,
});
});
return result;
}

View file

@ -122,3 +122,7 @@ private:
base::qt_connection _connection;
};
[[nodiscard]] base::unique_qptr<Ui::RpWidget> CreateDisabledFieldView(
QWidget *parent,
not_null<PeerData*> peer);

View file

@ -918,9 +918,9 @@ void TabbedSelector::checkRestrictedPeer() {
_currentPeer,
ChatRestriction::SendGifs)
: (_currentTabType == SelectorTab::Emoji && _mode == Mode::Full)
? (Data::RestrictionError(
_currentPeer,
ChatRestriction::SendInline)
? ((true || Data::RestrictionError(
_currentPeer, // We don't allow input if texts are forbidden.
ChatRestriction::SendInline))
? Data::RestrictionError(
_currentPeer,
ChatRestriction::SendOther)

View file

@ -1737,7 +1737,7 @@ void HistoryWidget::setInnerFocus() {
|| isRecording()
|| isBotStart()
|| isBlocked()
|| !_canSendMessages) {
|| !_canSendTexts) {
_list->setFocus();
} else {
_field->setFocus();
@ -1870,7 +1870,7 @@ void HistoryWidget::fastShowAtEnd(not_null<History*> history) {
void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
InvokeQueued(this, [=] { updateStickersByEmoji(); });
if (_voiceRecordBar->isActive()) {
if (_voiceRecordBar->isActive() || !_canSendTexts) {
return;
}
@ -1884,7 +1884,7 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
if (!draft || (!_history->localEditDraft({}) && !fieldAvailable)) {
auto fieldWillBeHiddenAfterEdit = (!fieldAvailable && _editMsgId != 0);
clearFieldText(0, fieldHistoryAction);
_field->setFocus();
setInnerFocus();
_processingReplyItem = _replyEditMsg = nullptr;
_processingReplyId = _replyToId = 0;
setEditMsgId(0);
@ -1898,7 +1898,7 @@ void HistoryWidget::applyDraft(FieldHistoryAction fieldHistoryAction) {
_textUpdateEvents = 0;
setFieldText(draft->textWithTags, 0, fieldHistoryAction);
_field->setFocus();
setInnerFocus();
draft->cursor.applyTo(_field);
_textUpdateEvents = TextUpdateEvent::SaveDraft
| TextUpdateEvent::SendTyping;
@ -2110,6 +2110,8 @@ void HistoryWidget::showHistory(
_list = nullptr;
_peer = nullptr;
_canSendMessages = false;
_canSendTexts = false;
_fieldDisabled = nullptr;
_silent.destroy();
updateBotKeyboard();
} else {
@ -2136,7 +2138,6 @@ void HistoryWidget::showHistory(
if (peerId) {
_peer = session().data().peer(peerId);
_canSendMessages = Data::CanSendAnything(_peer);
_contactStatus = std::make_unique<HistoryView::ContactStatus>(
controller(),
this,
@ -2628,6 +2629,13 @@ std::optional<QString> HistoryWidget::writeRestriction() const {
}
void HistoryWidget::updateControlsVisibility() {
auto fieldDisabledRemoved = (_fieldDisabled != nullptr);
const auto guard = gsl::finally([&] {
if (fieldDisabledRemoved) {
_fieldDisabled = nullptr;
}
});
if (!_showAnimation) {
_topShadow->setVisible(_peer != nullptr);
_topBar->setVisible(_peer != nullptr);
@ -2745,7 +2753,19 @@ void HistoryWidget::updateControlsVisibility() {
_send->show();
updateSendButtonType();
_field->show();
if (_canSendTexts) {
_field->show();
} else {
fieldDisabledRemoved = false;
if (!_fieldDisabled) {
_fieldDisabled = CreateDisabledFieldView(this, _peer);
orderWidgets();
updateControlsGeometry();
update();
}
_fieldDisabled->show();
hideFieldIfVisible();
}
if (_kbShown) {
_kbScroll->show();
_tabbedSelectorToggle->hide();
@ -3696,7 +3716,7 @@ void HistoryWidget::saveEditMsg() {
cancelEdit();
} else if (error == u"MESSAGE_EMPTY"_q) {
_field->selectAll();
_field->setFocus();
setInnerFocus();
} else {
controller()->showToast({ tr::lng_edit_error(tr::now) });
}
@ -3819,7 +3839,7 @@ void HistoryWidget::send(Api::SendOptions options) {
hideSelectorControlsAnimated();
if (_previewData && _previewData->pendingTill) previewCancel();
_field->setFocus();
setInnerFocus();
if (!_keyboard->hasMarkup() && _keyboard->forceReply() && !_kbReplyTo) {
toggleKeyboard();
@ -4260,7 +4280,7 @@ void HistoryWidget::sendBotCommand(const Bot::SendCommandRequest &request) {
}
}
_field->setFocus();
setInnerFocus();
}
void HistoryWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) {
@ -4281,7 +4301,7 @@ void HistoryWidget::hideSingleUseKeyboard(PeerData *peer, MsgId replyTo) {
}
bool HistoryWidget::insertBotCommand(const QString &cmd) {
if (!canWriteMessage()) {
if (!_canSendTexts) {
return false;
}
@ -4327,7 +4347,7 @@ bool HistoryWidget::insertBotCommand(const QString &cmd) {
{ toInsert, TextWithTags::Tags() },
TextUpdateEvent::SaveDraft,
Ui::InputField::HistoryAction::NewEntry);
_field->setFocus();
setInnerFocus();
return true;
}
return false;
@ -4808,10 +4828,20 @@ void HistoryWidget::recountChatWidth() {
controller()->adaptive().setChatLayout(layout);
}
int HistoryWidget::fieldHeight() const {
return _canSendTexts
? _field->height()
: (st::historySendSize.height() - 2 * st::historySendPadding);
}
bool HistoryWidget::fieldOrDisabledShown() const {
return !_field->isHidden() || _fieldDisabled;
}
void HistoryWidget::moveFieldControls() {
auto keyboardHeight = 0;
auto bottom = height();
auto maxKeyboardHeight = computeMaxFieldHeight() - _field->height();
auto maxKeyboardHeight = computeMaxFieldHeight() - fieldHeight();
_keyboard->resizeToWidth(width(), maxKeyboardHeight);
if (_kbShown) {
keyboardHeight = qMin(_keyboard->height(), maxKeyboardHeight);
@ -4834,6 +4864,11 @@ void HistoryWidget::moveFieldControls() {
_sendAs->moveToLeft(left, buttonsBottom); left += _sendAs->width();
}
_field->moveToLeft(left, bottom - _field->height() - st::historySendPadding);
if (_fieldDisabled) {
_fieldDisabled->moveToLeft(
left,
bottom - fieldHeight() - st::historySendPadding);
}
auto right = st::historySendRight;
_send->moveToRight(right, buttonsBottom); right += _send->width();
_voiceRecordBar->moveToLeft(0, bottom - _voiceRecordBar->height());
@ -4896,6 +4931,9 @@ void HistoryWidget::updateFieldSize() {
if (_scheduled) fieldWidth -= _scheduled->width();
if (_ttlInfo) fieldWidth -= _ttlInfo->width();
if (_fieldDisabled) {
_fieldDisabled->resize(fieldWidth, fieldHeight());
}
if (_field->width() != fieldWidth) {
_field->resize(fieldWidth, _field->height());
} else {
@ -5552,7 +5590,7 @@ void HistoryWidget::updateHistoryGeometry(
newScrollHeight -= _unblock->height();
} else {
if (editingMessage() || _canSendMessages) {
newScrollHeight -= (_field->height() + 2 * st::historySendPadding);
newScrollHeight -= (fieldHeight() + 2 * st::historySendPadding);
} else if (writeRestriction().has_value()) {
newScrollHeight -= _unblock->height();
}
@ -6197,7 +6235,7 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) {
hideSelectorControlsAnimated();
_field->setFocus();
setInnerFocus();
}
void HistoryWidget::updatePinnedViewer() {
@ -6690,7 +6728,7 @@ bool HistoryWidget::sendExistingDocument(
hideSelectorControlsAnimated();
_field->setFocus();
setInnerFocus();
return true;
}
@ -6715,7 +6753,7 @@ bool HistoryWidget::sendExistingPhoto(
hideSelectorControlsAnimated();
_field->setFocus();
setInnerFocus();
return true;
}
@ -6889,9 +6927,7 @@ void HistoryWidget::setReplyFieldsFromProcessing() {
_saveDraftStart = crl::now();
saveDraft();
if (!_field->isHidden()) {
_field->setFocus();
}
setInnerFocus();
}
void HistoryWidget::editMessage(FullMsgId itemId) {
@ -6961,7 +6997,9 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
updateBotKeyboard();
if (!_field->isHidden()) _fieldBarCancel->show();
if (fieldOrDisabledShown()) {
_fieldBarCancel->show();
}
updateFieldPlaceholder();
updateMouseTracking();
updateReplyToName();
@ -6972,7 +7010,7 @@ void HistoryWidget::editMessage(not_null<HistoryItem*> item) {
_saveDraftStart = crl::now();
saveDraft();
_field->setFocus();
setInnerFocus();
}
void HistoryWidget::hidePinnedMessage() {
@ -7328,10 +7366,15 @@ bool HistoryWidget::updateCanSendMessage() {
const auto newCanSendMessages = topic
? Data::CanSendAnyOf(topic, allWithoutPolls)
: Data::CanSendAnyOf(_peer, allWithoutPolls);
if (_canSendMessages == newCanSendMessages) {
const auto newCanSendTexts = topic
? Data::CanSend(topic, ChatRestriction::SendOther)
: Data::CanSend(_peer, ChatRestriction::SendOther);
if (_canSendMessages == newCanSendMessages
&& _canSendTexts == newCanSendTexts) {
return false;
}
_canSendMessages = newCanSendMessages;
_canSendTexts = newCanSendTexts;
if (!_canSendMessages) {
cancelReply();
}
@ -7474,7 +7517,7 @@ void HistoryWidget::updateTopBarSelection() {
|| isRecording()
|| isBotStart()
|| isBlocked()
|| !_canSendMessages) {
|| !_canSendTexts) {
_list->setFocus();
} else {
_field->setFocus();
@ -7504,7 +7547,7 @@ void HistoryWidget::updateReplyEditText(not_null<HistoryItem*> item) {
item->inReplyText(),
Ui::DialogTextOptions(),
context);
if (!_field->isHidden() || isRecording()) {
if (fieldOrDisabledShown() || isRecording()) {
_fieldBarCancel->show();
updateMouseTracking();
}
@ -7581,7 +7624,7 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
_repaintFieldScheduled = false;
auto backy = _field->y() - st::historySendPadding;
auto backh = _field->height() + 2 * st::historySendPadding;
auto backh = fieldHeight() + 2 * st::historySendPadding;
auto hasForward = readyToForward();
auto drawMsgText = (_editMsgId || _replyToId) ? _replyEditMsg : _kbReplyTo;
if (_editMsgId || _replyToId || (!hasForward && _kbReplyTo)) {
@ -7801,7 +7844,8 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto clip = e->rect();
if (_list) {
const auto restrictionHidden = !_field->isHidden() || isRecording();
const auto restrictionHidden = fieldOrDisabledShown()
|| isRecording();
if (restrictionHidden
|| replyToId()
|| readyToForward()
@ -7824,7 +7868,7 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
const auto tr = QRect(
(width() - w) / 2,
st::msgServiceMargin.top() + (height()
- _field->height()
- fieldHeight()
- 2 * st::historySendPadding
- h
- st::msgServiceMargin.top()

View file

@ -569,6 +569,8 @@ private:
void clearFieldText(
TextUpdateEvents events = 0,
FieldHistoryAction fieldHistoryAction = FieldHistoryAction::Clear);
[[nodiscard]] int fieldHeight() const;
[[nodiscard]] bool fieldOrDisabledShown() const;
void unregisterDraftSources();
void registerDraftSource();
@ -589,8 +591,8 @@ private:
void checkReplyReturns();
void scrollToAnimationCallback(FullMsgId attachToId, int relativeTo);
bool readyToForward() const;
bool hasSilentToggle() const;
[[nodiscard]] bool readyToForward() const;
[[nodiscard]] bool hasSilentToggle() const;
void checkSupportPreload(bool force = false);
void handleSupportSwitch(not_null<History*> updated);
@ -676,6 +678,7 @@ private:
PeerData *_peer = nullptr;
bool _canSendMessages = false;
bool _canSendTexts = false;
MsgId _showAtMsgId = ShowAtUnreadMsgId;
int _firstLoadRequest = 0; // Not real mtpRequestId.
@ -742,6 +745,7 @@ private:
std::unique_ptr<HistoryView::ComposeSearch> _composeSearch;
bool _cmdStartShown = false;
object_ptr<Ui::InputField> _field;
base::unique_qptr<Ui::RpWidget> _fieldDisabled;
bool _inReplyEditForward = false;
bool _inClickable = false;

View file

@ -1247,3 +1247,12 @@ historyTranslateSettings: IconButton(defaultIconButton) {
ripple: defaultRippleAnimation;
}
historyTranslateMenuPosition: point(-6px, 40px);
historySendDisabled: FlatLabel(defaultFlatLabel) {
minWidth: 10px;
maxHeight: 20px;
textFg: placeholderFg;
}
historySendDisabledIcon: icon {{ "emoji/premium_lock", placeholderFgActive }};
historySendDisabledIconSkip: 20px;
historySendDisabledPosition: point(0px, 0px);