Add supergroup restriction placeholders / labels.

This commit is contained in:
John Preston 2017-06-11 20:33:20 +02:00
parent 7d2d5c6100
commit 5c0a1bafe2
15 changed files with 462 additions and 59 deletions

View File

@ -141,7 +141,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_error_pinned_max#other" = "Sorry, you can pin no more than {count} chats to the top.";
"lng_error_public_groups_denied" = "Unfortunately, you were banned from participating in public groups.\n{more_info}";
"lng_error_cant_edit_admin" = "Sorry, you can't edit permissions for this admin.";
"lng_error_cant_add_member" = "Sorry, you can't add the bot to this group.";
"lng_error_cant_add_member" = "Sorry, you can't add the bot to this group. Ask a group admin to do it.";
"lng_edit_deleted" = "This message was deleted";
"lng_edit_too_long" = "Your message text is too long";
@ -1060,8 +1060,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_forward_cant" = "Sorry, no way to forward here :(";
"lng_forward_confirm" = "Forward to {recipient}?";
"lng_forward_share_contact" = "Share contact to {recipient}?";
"lng_forward_share_cant" = "Sorry, no way to share contact here :(";
"lng_forward_send_file_confirm" = "Send «{name}» to {recipient}?";
"lng_forward_send_files_confirm" = "Send selected files to {recipient}?";
"lng_forward_send_files_cant" = "Sorry, no way to send media here :(";
"lng_forward_send" = "Send";
"lng_forward_messages#one" = "{count} forwarded message";
"lng_forward_messages#other" = "{count} forwarded messages";
@ -1275,6 +1277,12 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
"lng_rights_chat_banned_forever" = "Forever";
"lng_rights_chat_banned_block" = "Block and remove from group";
"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_stickers" = "The admins of this group restricted you from posting stickers here.";
"lng_restricted_send_gifs" = "The admins of this group restricted you from posting GIFs here.";
"lng_restricted_send_inline" = "The admins of this group restricted you from posting inline content here.";
// Not used
"lng_topbar_info" = "Info";

View File

@ -884,6 +884,25 @@ void shareGameScoreFromItem(HistoryItem *item) {
if (!data->requests.empty()) {
return; // Share clicked already.
}
if (result.empty()) {
return;
}
auto restrictedEverywhere = true;
auto restrictedSomewhere = false;
for_const (auto peer, result) {
if (auto megagroup = peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_games()) {
restrictedSomewhere = true;
continue;
}
}
restrictedEverywhere = false;
}
if (restrictedEverywhere) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_inline)), KeepOtherLayers);
return;
}
auto doneCallback = [data](const MTPUpdates &updates, mtpRequestId requestId) {
if (auto main = App::main()) {
@ -901,6 +920,12 @@ void shareGameScoreFromItem(HistoryItem *item) {
if (auto main = App::main()) {
if (auto item = App::histItemById(data->msgId)) {
for_const (auto peer, result) {
if (auto megagroup = peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_games()) {
continue;
}
}
MTPVector<MTPlong> random = MTP_vector<MTPlong>(1, rand_value<MTPlong>());
auto request = MTPmessages_ForwardMessages(MTP_flags(sendFlags), item->history()->peer->input, msgIds, random, peer->input);
auto callback = doneCallback;

View File

@ -28,6 +28,11 @@ switchPmButton: RoundButton(defaultBoxButton) {
height: 34px;
textTop: 7px;
}
stickersRestrictedLabel: FlatLabel(defaultFlatLabel) {
width: 320px;
align: align(center);
textFg: noContactsColor;
}
stickersTrendingHeader: 45px;
stickersTrendingSkip: 15px;

View File

@ -26,12 +26,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "chat_helpers/stickers.h"
#include "styles/style_chat_helpers.h"
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/widgets/shadow.h"
#include "ui/widgets/discrete_sliders.h"
#include "ui/widgets/scroll_area.h"
#include "storage/localstorage.h"
#include "lang/lang_keys.h"
#include "mainwindow.h"
#include "observer_peer.h"
namespace ChatHelpers {
namespace {
@ -46,7 +48,7 @@ public:
LeftToRight,
RightToLeft,
};
void setFinalImages(Direction direction, QImage &&left, QImage &&right, QRect inner);
void setFinalImages(Direction direction, QImage &&left, QImage &&right, QRect inner, bool wasSectionIcons);
void start();
void paintFrame(QPainter &p, float64 dt, float64 opacity);
@ -72,10 +74,11 @@ private:
int _painterInnerRight = 0;
int _frameIntsPerLineAdd = 0;
bool _wasSectionIcons = false;
};
void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage &&left, QImage &&right, QRect inner) {
void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage &&left, QImage &&right, QRect inner, bool wasSectionIcons) {
Expects(!started());
_direction = direction;
_leftImage = QPixmap::fromImage(std::move(left).convertToFormat(QImage::Format_ARGB32_Premultiplied), Qt::ColorOnly);
@ -109,6 +112,8 @@ void TabbedSelector::SlideAnimation::setFinalImages(Direction direction, QImage
_painterInnerWidth = _innerWidth / cIntRetinaFactor();
_painterInnerHeight = _innerHeight / cIntRetinaFactor();
_painterCategoriesTop = _painterInnerBottom - st::emojiCategory.height;
_wasSectionIcons = wasSectionIcons;
}
void TabbedSelector::SlideAnimation::start() {
@ -166,7 +171,7 @@ void TabbedSelector::SlideAnimation::paintFrame(QPainter &p, float64 dt, float64
Painter p(&_frame);
p.setOpacity(opacity);
p.fillRect(_painterInnerLeft, _painterInnerTop, _painterInnerWidth, _painterCategoriesTop - _painterInnerTop, st::emojiPanBg);
p.fillRect(_painterInnerLeft, _painterCategoriesTop, _painterInnerWidth, _painterInnerBottom - _painterCategoriesTop, st::emojiPanCategories);
p.fillRect(_painterInnerLeft, _painterCategoriesTop, _painterInnerWidth, _painterInnerBottom - _painterCategoriesTop, _wasSectionIcons ? st::emojiPanCategories : st::emojiPanBg);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
if (leftTo > _innerLeft) {
p.setOpacity(opacity * leftAlpha);
@ -337,6 +342,12 @@ TabbedSelector::TabbedSelector(QWidget *parent, gsl::not_null<Window::Controller
_bottomShadow->raise();
_tabsSlider->raise();
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::ChannelRightsChanged, [this](const Notify::PeerUpdate &update) {
if (update.peer == _currentPeer) {
checkRestrictedPeer();
}
}));
// setAttribute(Qt::WA_AcceptTouchEvents);
setAttribute(Qt::WA_OpaquePaintEvent, false);
showAll();
@ -354,6 +365,9 @@ void TabbedSelector::resizeEvent(QResizeEvent *e) {
_scroll->resize(_scroll->width(), contentHeight);
}
_bottomShadow->setGeometry(_tabsSlider->x(), _scroll->y() + _scroll->height() - st::lineWidth, _tabsSlider->width(), st::lineWidth);
if (_restrictedLabel) {
_restrictedLabel->move((width() - _restrictedLabel->width()), (height() / 3 - _restrictedLabel->height() / 2));
}
_footerTop = height() - st::emojiCategory.height;
for (auto &tab : _tabs) {
@ -394,8 +408,7 @@ void TabbedSelector::paintSlideFrame(Painter &p, TimeMs ms) {
}
void TabbedSelector::paintContent(Painter &p) {
auto showSectionIcons = (_currentTabType != SelectorTab::Gifs);
auto &bottomBg = showSectionIcons ? st::emojiPanCategories : st::emojiPanBg;
auto &bottomBg = hasSectionIcons() ? st::emojiPanCategories : st::emojiPanBg;
if (_roundRadius > 0) {
auto topPart = QRect(0, 0, width(), _tabsSlider->height() + _roundRadius);
App::roundRect(p, topPart, st::emojiPanBg, ImageRoundRadius::Small, RectPart::FullTop | RectPart::NoTopBottom);
@ -410,8 +423,12 @@ void TabbedSelector::paintContent(Painter &p) {
auto sidesTop = marginTop();
auto sidesHeight = height() - sidesTop - marginBottom();
p.fillRect(myrtlrect(width() - st::emojiScroll.width, sidesTop, st::emojiScroll.width, sidesHeight), st::emojiPanBg);
p.fillRect(myrtlrect(0, sidesTop, st::buttonRadius, sidesHeight), st::emojiPanBg);
if (_restrictedLabel) {
p.fillRect(0, sidesTop, width(), sidesHeight, st::emojiPanBg);
} else {
p.fillRect(myrtlrect(width() - st::emojiScroll.width, sidesTop, st::emojiScroll.width, sidesHeight), st::emojiPanBg);
p.fillRect(myrtlrect(0, sidesTop, st::buttonRadius, sidesHeight), st::emojiPanBg);
}
}
int TabbedSelector::marginTop() const {
@ -504,15 +521,56 @@ void TabbedSelector::stickersInstalled(uint64 setId) {
stickers()->showStickerSet(setId);
}
void TabbedSelector::setInlineQueryPeer(PeerData *peer) {
void TabbedSelector::setCurrentPeer(PeerData *peer) {
gifs()->setInlineQueryPeer(peer);
_currentPeer = peer;
checkRestrictedPeer();
}
void TabbedSelector::checkRestrictedPeer() {
if (auto megagroup = _currentPeer ? _currentPeer->asMegagroup() : nullptr) {
auto restricted = (_currentTabType == SelectorTab::Stickers) ? megagroup->restrictedRights().is_send_stickers() :
(_currentTabType == SelectorTab::Gifs) ? megagroup->restrictedRights().is_send_gifs() : false;
if (restricted) {
if (!_restrictedLabel) {
auto text = (_currentTabType == SelectorTab::Stickers) ? lang(lng_restricted_send_stickers) :
(_currentTabType == SelectorTab::Gifs) ? lang(lng_restricted_send_gifs) : false;
_restrictedLabel.create(this, text, Ui::FlatLabel::InitType::Simple, st::stickersRestrictedLabel);
_restrictedLabel->show();
_restrictedLabel->move((width() - _restrictedLabel->width()), (height() / 3 - _restrictedLabel->height() / 2));
currentTab()->footer()->hide();
_scroll->hide();
_bottomShadow->hide();
update();
}
return;
}
}
if (_restrictedLabel) {
_restrictedLabel.destroy();
if (!_a_slide.animating()) {
currentTab()->footer()->show();
_scroll->show();
_bottomShadow->setVisible(_currentTabType == SelectorTab::Gifs);
update();
}
}
}
bool TabbedSelector::isRestrictedView() {
checkRestrictedPeer();
return (_restrictedLabel != nullptr);
}
void TabbedSelector::showAll() {
currentTab()->footer()->show();
_scroll->show();
if (isRestrictedView()) {
_restrictedLabel->show();
} else {
currentTab()->footer()->show();
_scroll->show();
_bottomShadow->setVisible(_currentTabType == SelectorTab::Gifs);
}
_topShadow->show();
_bottomShadow->setVisible(_currentTabType == SelectorTab::Gifs);
_tabsSlider->show();
}
@ -551,6 +609,10 @@ void TabbedSelector::createTabsSlider() {
_topShadow->setGeometry(_tabsSlider->x(), _tabsSlider->bottomNoMargins() - st::lineWidth, _tabsSlider->width(), st::lineWidth);
}
bool TabbedSelector::hasSectionIcons() const {
return (_currentTabType != SelectorTab::Gifs) && !_restrictedLabel;
}
void TabbedSelector::switchTab() {
auto tab = _tabsSlider->activeSection();
t_assert(tab >= 0 && tab < Tab::kCount);
@ -559,6 +621,7 @@ void TabbedSelector::switchTab() {
return;
}
auto wasSectionIcons = hasSectionIcons();
auto wasTab = _currentTabType;
currentTab()->saveScrollTop();
@ -573,6 +636,9 @@ void TabbedSelector::switchTab() {
currentTab()->returnWidget(std::move(widget));
_currentTabType = newTabType;
_restrictedLabel.destroy();
checkRestrictedPeer();
currentTab()->widget()->refreshRecent();
currentTab()->widget()->preloadImages();
setWidgetToScrollArea();
@ -585,7 +651,7 @@ void TabbedSelector::switchTab() {
}
_slideAnimation = std::make_unique<SlideAnimation>();
auto slidingRect = QRect(_tabsSlider->x() * cIntRetinaFactor(), _scroll->y() * cIntRetinaFactor(), _tabsSlider->width() * cIntRetinaFactor(), (height() - _scroll->y()) * cIntRetinaFactor());
_slideAnimation->setFinalImages(direction, std::move(wasCache), std::move(nowCache), slidingRect);
_slideAnimation->setFinalImages(direction, std::move(wasCache), std::move(nowCache), slidingRect, wasSectionIcons);
auto corners = App::cornersMask(ImageRoundRadius::Small);
_slideAnimation->setCornerMasks(QImage(*corners[0]), QImage(*corners[1]), QImage(*corners[2]), QImage(*corners[3]));
_slideAnimation->start();

View File

@ -33,6 +33,7 @@ namespace Ui {
class PlainShadow;
class ScrollArea;
class SettingsSlider;
class FlatLabel;
} // namesapce Ui
namespace Window {
@ -51,7 +52,7 @@ class EmojiListWidget;
class StickersListWidget;
class GifsListWidget;
class TabbedSelector : public TWidget {
class TabbedSelector : public TWidget, private base::Subscriber {
Q_OBJECT
public:
@ -60,7 +61,7 @@ public:
void setRoundRadius(int radius);
void refreshStickers();
void stickersInstalled(uint64 setId);
void setInlineQueryPeer(PeerData *peer);
void setCurrentPeer(PeerData *peer);
void hideFinished();
void showStarted();
@ -150,6 +151,9 @@ private:
void paintSlideFrame(Painter &p, TimeMs ms);
void paintContent(Painter &p);
void checkRestrictedPeer();
bool isRestrictedView();
QImage grabForAnimation();
void scrollToY(int y);
@ -157,6 +161,7 @@ private:
void showAll();
void hideForSliding();
bool hasSectionIcons() const;
void setWidgetToScrollArea();
void createTabsSlider();
void switchTab();
@ -178,6 +183,7 @@ private:
int _roundRadius = 0;
int _footerTop = 0;
PeerData *_currentPeer = nullptr;
class SlideAnimation;
std::unique_ptr<SlideAnimation> _slideAnimation;
@ -187,6 +193,7 @@ private:
object_ptr<Ui::PlainShadow> _topShadow;
object_ptr<Ui::PlainShadow> _bottomShadow;
object_ptr<Ui::ScrollArea> _scroll;
object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
std::array<Tab, Tab::kCount> _tabs;
SelectorTab _currentTabType = SelectorTab::Emoji;

View File

@ -2947,10 +2947,9 @@ void DialogsWidget::updateDragInScroll(bool inScroll) {
void DialogsWidget::dropEvent(QDropEvent *e) {
_chooseByDragTimer.stop();
if (_scroll->geometry().contains(e->pos())) {
PeerData *p = _inner->updateFromParentDrag(mapToGlobal(e->pos()));
if (p) {
if (auto peer = _inner->updateFromParentDrag(mapToGlobal(e->pos()))) {
e->acceptProposedAction();
App::main()->onFilesOrForwardDrop(p->id, e->mimeData());
App::main()->onFilesOrForwardDrop(peer->id, e->mimeData());
}
}
}

View File

@ -85,6 +85,8 @@ constexpr auto kTabbedSelectorToggleTooltipCount = 3;
constexpr auto kScrollToVoiceAfterScrolledMs = 1000;
constexpr auto kSkipRepaintWhileScrollMs = 100;
constexpr auto kShowMembersDropdownTimeoutMs = 300;
constexpr auto kDisplayEditTimeWarningMs = 300 * 1000;
constexpr auto kFullDayInMs = 86400 * 1000;
ApiWrap::RequestMessageDataCallback replyEditMessageDataCallback() {
return [](ChannelData *channel, MsgId msgId) {
@ -363,8 +365,16 @@ bool HistoryHider::offerPeer(PeerId peer) {
}
_offered = App::peer(peer);
auto phrase = QString();
QString recipient = _offered->isUser() ? _offered->name : '\xAB' + _offered->name + '\xBB';
auto recipient = _offered->isUser() ? _offered->name : '\xAB' + _offered->name + '\xBB';
if (_sharedContact) {
if (!_offered->canWrite()) {
Ui::show(Box<InformBox>(lang(lng_forward_share_cant)));
_offered = nullptr;
_toText.setText(st::boxLabelStyle, QString());
_toTextWidth = 0;
resizeEvent(nullptr);
return false;
}
phrase = lng_forward_share_contact(lt_recipient, recipient);
} else if (_sendPath) {
auto toId = _offered->id;
@ -650,6 +660,11 @@ HistoryWidget::HistoryWidget(QWidget *parent, gsl::not_null<Window::Controller*>
scrollToCurrentVoiceMessage(pair.from.contextId(), pair.to);
}
});
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::ChannelRightsChanged, [this](const Notify::PeerUpdate &update) {
if (update.peer == _peer) {
onPreviewCheck();
}
}));
orderWidgets();
}
@ -1879,7 +1894,7 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
_peer = App::peer(peerId);
_channel = peerToChannel(_peer->id);
_canSendMessages = canSendMessages(_peer);
_tabbedSelector->setInlineQueryPeer(_peer);
_tabbedSelector->setCurrentPeer(_peer);
}
updateTopBarSelection();
@ -2143,6 +2158,13 @@ bool HistoryWidget::canWriteMessage() const {
return true;
}
bool HistoryWidget::isRestrictedWrite() const {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
return megagroup->restrictedRights().is_send_messages();
}
return false;
}
void HistoryWidget::updateControlsVisibility() {
if (!_a_show.animating()) {
_topShadow->setVisible(_peer != nullptr);
@ -3198,7 +3220,13 @@ void HistoryWidget::step_recording(float64 ms, bool timer) {
}
void HistoryWidget::chooseAttach() {
if (!_history) return;
if (!_peer || !_peer->canWrite()) return;
if (auto megagroup = _peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_media()) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_media)));
return;
}
}
auto filter = FileDialog::AllFilesFilter() + qsl(";;Image files (*") + cImgExtensions().join(qsl(" *")) + qsl(")");
@ -3297,6 +3325,13 @@ void HistoryWidget::recordStartCallback() {
if (!Media::Capture::instance()->available()) {
return;
}
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restrictedRights().is_send_media()) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_media)));
return;
}
}
emit Media::Capture::instance()->start();
_recording = _inField = true;
@ -4307,6 +4342,12 @@ bool HistoryWidget::confirmSendingFiles(const QStringList &files, CompressConfir
}
bool HistoryWidget::confirmSendingFiles(const SendingFilesLists &lists, CompressConfirm compressed, const QString *addedComment) {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restrictedRights().is_send_media()) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_media)));
return false;
}
}
return validateSendingFiles(lists, [this, &lists, compressed, addedComment](const QStringList &files) {
auto insertTextOnCancel = QString();
auto sendCallback = [this](const QStringList &files, const QImage &image, std::unique_ptr<FileLoadTask::MediaInformation> information, bool compressed, const QString &caption, MsgId replyTo) {
@ -4955,6 +4996,8 @@ void HistoryWidget::updateHistoryGeometry(bool initial, bool loadedDown, const S
} else {
if (_canSendMessages) {
newScrollHeight -= (_field->height() + 2 * st::historySendPadding);
} else if (isRestrictedWrite()) {
newScrollHeight -= _unblock->height();
}
if (_editMsgId || replyToId() || readyToForward() || (_previewData && _previewData->pendingTill >= 0)) {
newScrollHeight -= st::historyReplyHeight;
@ -5268,16 +5311,34 @@ void HistoryWidget::onFieldTabbed() {
}
bool HistoryWidget::onStickerSend(DocumentData *sticker) {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restrictedRights().is_send_stickers()) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_stickers)), KeepOtherLayers);
return false;
}
}
return sendExistingDocument(sticker, QString());
}
void HistoryWidget::onPhotoSend(PhotoData *photo) {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restrictedRights().is_send_media()) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_media)), KeepOtherLayers);
return;
}
}
sendExistingPhoto(photo, QString());
}
void HistoryWidget::onInlineResultSend(InlineBots::Result *result, UserData *bot) {
if (!_history || !result || !canSendMessages(_peer)) return;
auto errorText = result->getErrorOnSend(_history);
if (!errorText.isEmpty()) {
Ui::show(Box<InformBox>(errorText));
return;
}
App::main()->readServerHistory(_history);
fastShowAtEnd(_history);
@ -5867,8 +5928,7 @@ void HistoryWidget::onStickerPackInfo() {
}
void HistoryWidget::previewCancel() {
MTP::cancel(_previewRequest);
_previewRequest = 0;
MTP::cancel(base::take(_previewRequest));
_previewData = nullptr;
_previewLinks.clear();
updatePreview();
@ -5884,11 +5944,25 @@ void HistoryWidget::onPreviewParse() {
}
void HistoryWidget::onPreviewCheck() {
if (_previewCancelled) return;
QStringList linksList = _field->linksList();
QString newLinks = linksList.join(' ');
auto previewRestricted = [this] {
if (auto megagroup = _peer ? _peer->asMegagroup() : nullptr) {
if (megagroup->restrictedRights().is_embed_links()) {
return true;
}
}
return false;
};
if (_previewCancelled || previewRestricted()) {
MTP::cancel(base::take(_previewRequest));
_previewData = nullptr;
_previewLinks.clear();
update();
return;
}
auto linksList = _field->linksList();
auto newLinks = linksList.join(' ');
if (newLinks != _previewLinks) {
MTP::cancel(_previewRequest);
MTP::cancel(base::take(_previewRequest));
_previewLinks = newLinks;
if (_previewLinks.isEmpty()) {
if (_previewData && _previewData->pendingTill >= 0) previewCancel();
@ -6397,12 +6471,14 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
}
}
namespace {
void HistoryWidget::drawRestrictedWrite(Painter &p) {
auto rect = myrtlrect(0, height() - _unblock->height(), _chatWidth, _unblock->height());
p.fillRect(rect, st::historyReplyBg);
constexpr int DisplayEditTimeWarningMs = 300 * 1000;
constexpr int FullDayInMs = 86400 * 1000;
} // namespace
p.setFont(st::normalFont);
p.setPen(st::windowSubTextFg);
p.drawText(rect.marginsRemoved(QMargins(st::historySendPadding, 0, st::historySendPadding, 0)), lang(lng_restricted_send_message), style::al_center);
}
void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int top) const {
if (!rect.intersects(myrtlrect(left, top, _chatWidth - left, st::normalFont->height))) {
@ -6421,8 +6497,8 @@ void HistoryWidget::paintEditHeader(Painter &p, const QRect &rect, int left, int
auto editTimeLeft = (Global::EditTimeLimit() * 1000LL) - timeSinceMessage;
if (editTimeLeft < 2) {
editTimeLeftText = qsl("0:00");
} else if (editTimeLeft > DisplayEditTimeWarningMs) {
updateIn = static_cast<int>(qMin(editTimeLeft - DisplayEditTimeWarningMs, qint64(FullDayInMs)));
} else if (editTimeLeft > kDisplayEditTimeWarningMs) {
updateIn = static_cast<int>(qMin(editTimeLeft - kDisplayEditTimeWarningMs, qint64(kFullDayInMs)));
} else {
updateIn = static_cast<int>(editTimeLeft % 1000);
if (!updateIn) {
@ -6583,6 +6659,8 @@ void HistoryWidget::paintEvent(QPaintEvent *e) {
if (!_send->isHidden() && _recording) {
drawRecording(p, _send->recordActiveRatio());
}
} else if (isRestrictedWrite()) {
drawRestrictedWrite(p);
}
if (_pinnedBar && !_pinnedBar->cancel->isHidden()) {
drawPinnedBar(p);

View File

@ -523,6 +523,7 @@ private:
bool historyHasNotFreezedUnreadBar(History *history) const;
bool canWriteMessage() const;
bool isRestrictedWrite() const;
void orderWidgets();
void clearInlineBot();
@ -577,6 +578,7 @@ private:
void paintEditHeader(Painter &p, const QRect &rect, int left, int top) const;
void drawRecording(Painter &p, float64 recordActive);
void drawPinnedBar(Painter &p);
void drawRestrictedWrite(Painter &p);
void updateMouseTracking();

View File

@ -290,6 +290,10 @@ void Result::addToHistory(History *history, MTPDmessage::Flags flags, MsgId msgI
sendData->addToHistory(this, history, flags, msgId, fromId, mtpDate, viaBotId, replyToId, markup);
}
QString Result::getErrorOnSend(History *history) const {
return sendData->getErrorOnSend(this, history);
}
bool Result::getLocationCoords(LocationCoords *outLocation) const {
return sendData->getLocationCoords(outLocation);
}

View File

@ -68,6 +68,7 @@ public:
bool hasThumbDisplay() const;
void addToHistory(History *history, MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate, UserId viaBotId, MsgId replyToId) const;
QString getErrorOnSend(History *history) const;
// interface for Layout:: usage
bool getLocationCoords(LocationCoords *outLocation) const;

View File

@ -22,6 +22,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "inline_bots/inline_bot_result.h"
#include "storage/localstorage.h"
#include "lang/lang_keys.h"
namespace InlineBots {
namespace internal {
@ -44,6 +45,15 @@ UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const {
history->addNewMessage(MTP_message(MTP_flags(flags), MTP_int(msgId), MTP_int(fromId), peerToMTP(history->peer->id), MTPnullFwdHeader, MTP_int(viaBotId), MTP_int(replyToId), mtpDate, fields.text, fields.media, markup, fields.entities, MTP_int(1), MTPint()), NewMessageUnread);
}
QString SendDataCommon::getErrorOnSend(const Result *owner, History *history) const {
if (auto megagroup = history->peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_messages()) {
return lang(lng_restricted_send_message);
}
}
return QString();
}
SendDataCommon::SentMTPMessageFields SendText::getSentMessageFields() const {
SentMTPMessageFields result;
result.text = MTP_string(_message);
@ -83,17 +93,48 @@ UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const {
history->addNewPhoto(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, _photo, _caption, markup);
}
QString SendPhoto::getErrorOnSend(const Result *owner, History *history) const {
if (auto megagroup = history->peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_media()) {
return lang(lng_restricted_send_media);
}
}
return QString();
}
void SendFile::addToHistory(const Result *owner, History *history,
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const {
history->addNewDocument(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, _document, _caption, markup);
}
QString SendFile::getErrorOnSend(const Result *owner, History *history) const {
if (auto megagroup = history->peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_media()) {
return lang(lng_restricted_send_media);
} else if (megagroup->restrictedRights().is_send_stickers() && (_document->sticker() != nullptr)) {
return lang(lng_restricted_send_stickers);
} else if (megagroup->restrictedRights().is_send_gifs() && _document->isAnimation() && !_document->isRoundVideo()) {
return lang(lng_restricted_send_gifs);
}
}
return QString();
}
void SendGame::addToHistory(const Result *owner, History *history,
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const {
history->addNewGame(msgId, flags, viaBotId, replyToId, date(mtpDate), fromId, _game, markup);
}
QString SendGame::getErrorOnSend(const Result *owner, History *history) const {
if (auto megagroup = history->peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_games()) {
return lang(lng_restricted_send_inline);
}
}
return QString();
}
} // namespace internal
} // namespace InlineBots

View File

@ -46,6 +46,7 @@ public:
virtual void addToHistory(const Result *owner, History *history,
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const = 0;
virtual QString getErrorOnSend(const Result *owner, History *history) const = 0;
virtual bool hasLocationCoords() const {
return false;
@ -74,6 +75,8 @@ public:
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const override;
QString getErrorOnSend(const Result *owner, History *history) const override;
};
// Plain text message.
@ -193,6 +196,8 @@ public:
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const override;
QString getErrorOnSend(const Result *owner, History *history) const override;
private:
PhotoData *_photo;
QString _caption;
@ -215,6 +220,8 @@ public:
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const override;
QString getErrorOnSend(const Result *owner, History *history) const override;
private:
DocumentData *_document;
QString _caption;
@ -236,6 +243,8 @@ public:
MTPDmessage::Flags flags, MsgId msgId, UserId fromId, MTPint mtpDate,
UserId viaBotId, MsgId replyToId, const MTPReplyMarkup &markup) const override;
QString getErrorOnSend(const Result *owner, History *history) const override;
private:
GameData *_game;

View File

@ -36,6 +36,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "auth_session.h"
#include "window/window_controller.h"
#include "ui/widgets/scroll_area.h"
#include "ui/widgets/labels.h"
#include "observer_peer.h"
namespace InlineBots {
namespace Layout {
@ -67,6 +69,15 @@ Inner::Inner(QWidget *parent, gsl::not_null<Window::Controller*> controller) : T
update();
}
});
subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(Notify::PeerUpdate::Flag::ChannelRightsChanged, [this](const Notify::PeerUpdate &update) {
if (update.peer == _inlineQueryPeer) {
auto isRestricted = (_restrictedLabel != nullptr);
if (isRestricted != isRestrictedView()) {
auto h = countHeight();
if (h != height()) resize(width(), h);
}
}
}));
}
void Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
@ -77,7 +88,39 @@ void Inner::setVisibleTopBottom(int visibleTop, int visibleBottom) {
}
}
void Inner::checkRestrictedPeer() {
if (auto megagroup = _inlineQueryPeer ? _inlineQueryPeer->asMegagroup() : nullptr) {
if (megagroup->restrictedRights().is_send_inline()) {
if (!_restrictedLabel) {
_restrictedLabel.create(this, lang(lng_restricted_send_inline), Ui::FlatLabel::InitType::Simple, st::stickersRestrictedLabel);
_restrictedLabel->show();
_restrictedLabel->move(st::inlineResultsLeft - st::buttonRadius, st::stickerPanPadding);
if (_switchPmButton) {
_switchPmButton->hide();
}
update();
}
return;
}
}
if (_restrictedLabel) {
_restrictedLabel.destroy();
if (_switchPmButton) {
_switchPmButton->show();
}
update();
}
}
bool Inner::isRestrictedView() {
checkRestrictedPeer();
return (_restrictedLabel != nullptr);
}
int Inner::countHeight() {
if (isRestrictedView()) {
return st::stickerPanPadding + _restrictedLabel->height() + st::stickerPanPadding;
}
auto result = st::stickerPanPadding;
if (_switchPmButton) {
result += _switchPmButton->height() + st::inlineResultsSkip;
@ -102,6 +145,9 @@ void Inner::paintEvent(QPaintEvent *e) {
}
void Inner::paintInlineItems(Painter &p, const QRect &r) {
if (_restrictedLabel) {
return;
}
if (_rows.isEmpty() && !_switchPmButton) {
p.setFont(st::normalFont);
p.setPen(st::noContactsColor);
@ -278,7 +324,7 @@ bool Inner::inlineRowFinalize(Row &row, int32 &sumWidth, bool force) {
}
void Inner::inlineBotChanged() {
refreshInlineRows(nullptr, nullptr, true);
refreshInlineRows(nullptr, nullptr, nullptr, true);
}
void Inner::clearInlineRows(bool resultsDeleted) {
@ -392,12 +438,16 @@ void Inner::refreshSwitchPmButton(const CacheEntry *entry) {
_switchPmStartToken = entry->switchPmStartToken;
auto buttonTop = st::stickerPanPadding;
_switchPmButton->move(st::inlineResultsLeft - st::buttonRadius, buttonTop);
if (isRestrictedView()) {
_switchPmButton->hide();
}
}
update();
}
int Inner::refreshInlineRows(UserData *bot, const CacheEntry *entry, bool resultsDeleted) {
int Inner::refreshInlineRows(PeerData *queryPeer, UserData *bot, const CacheEntry *entry, bool resultsDeleted) {
_inlineBot = bot;
_inlineQueryPeer = queryPeer;
refreshSwitchPmButton(entry);
auto clearResults = [this, entry]() {
if (!entry) {
@ -1072,7 +1122,7 @@ bool Widget::refreshInlineRows(int *added) {
_inlineNextOffset = it->second->nextOffset;
}
if (!entry) prepareCache();
auto result = _inner->refreshInlineRows(_inlineBot, entry, false);
auto result = _inner->refreshInlineRows(_inlineQueryPeer, _inlineBot, entry, false);
if (added) *added = result;
return (entry != nullptr);
}

View File

@ -31,6 +31,7 @@ class ScrollArea;
class IconButton;
class LinkButton;
class RoundButton;
class FlatLabel;
class RippleAnimation;
} // namesapce Ui
@ -68,7 +69,7 @@ public:
void clearSelection();
int refreshInlineRows(UserData *bot, const CacheEntry *results, bool resultsDeleted);
int refreshInlineRows(PeerData *queryPeer, UserData *bot, const CacheEntry *results, bool resultsDeleted);
void inlineBotChanged();
void hideInlineRowsPanel();
void clearInlineRowsPanel();
@ -110,6 +111,8 @@ private:
static constexpr bool kRefreshIconsNoAnimation = false;
void updateSelected();
void checkRestrictedPeer();
bool isRestrictedView();
void paintInlineItems(Painter &p, const QRect &r);
@ -120,7 +123,8 @@ private:
int _visibleTop = 0;
int _visibleBottom = 0;
UserData *_inlineBot;
UserData *_inlineBot = nullptr;
PeerData *_inlineQueryPeer = nullptr;
TimeMs _lastScrolled = 0;
QTimer _updateInlineItems;
bool _inlineWithThumb = false;
@ -128,6 +132,8 @@ private:
object_ptr<Ui::RoundButton> _switchPmButton = { nullptr };
QString _switchPmStartToken;
object_ptr<Ui::FlatLabel> _restrictedLabel = { nullptr };
struct Row {
int height = 0;
QVector<ItemBase*> items;

View File

@ -77,7 +77,7 @@ namespace {
constexpr auto kSaveFloatPlayerPositionTimeoutMs = TimeMs(1000);
MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
MTPMessagesFilter TypeToMediaFilter(MediaOverviewType &type) {
switch (type) {
case OverviewPhotos: return MTP_inputMessagesFilterPhotos();
case OverviewVideos: return MTP_inputMessagesFilterVideo();
@ -92,6 +92,64 @@ MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
}
}
bool HasMediaItems(const SelectedItemSet &items) {
for_const (auto item, items) {
if (auto media = item->getMedia()) {
switch (media->type()) {
case MediaTypePhoto:
case MediaTypeVideo:
case MediaTypeFile:
case MediaTypeMusicFile:
case MediaTypeVoiceFile: return true;
case MediaTypeGif: return media->getDocument()->isRoundVideo();
}
}
}
return false;
}
bool HasStickerItems(const SelectedItemSet &items) {
for_const (auto item, items) {
if (auto media = item->getMedia()) {
switch (media->type()) {
case MediaTypeSticker: return true;
}
}
}
return false;
}
bool HasGifItems(const SelectedItemSet &items) {
for_const (auto item, items) {
if (auto media = item->getMedia()) {
switch (media->type()) {
case MediaTypeGif: return !media->getDocument()->isRoundVideo();
}
}
}
return false;
}
bool HasGameItems(const SelectedItemSet &items) {
for_const (auto item, items) {
if (auto media = item->getMedia()) {
switch (media->type()) {
case MediaTypeGame: return true;
}
}
}
return false;
}
bool HasInlineItems(const SelectedItemSet &items) {
for_const (auto item, items) {
if (item->viaBot()) {
return true;
}
}
return false;
}
} // namespace
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
@ -505,22 +563,33 @@ void MainWidget::finishFloatPlayerDrag(gsl::not_null<Float*> instance, bool clos
}
}
bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) {
PeerData *p = App::peer(peer);
if (!peer || (p->isChannel() && !p->asChannel()->canPublish() && p->asChannel()->isBroadcast()) || (p->isChat() && !p->asChat()->canWrite()) || (p->isUser() && p->asUser()->isInaccessible())) {
Ui::show(Box<InformBox>(lang(lng_forward_cant)));
bool MainWidget::onForward(const PeerId &peerId, ForwardWhatMessages what) {
Expects(peerId != 0);
auto peer = App::peer(peerId);
auto finishWithError = [this, what](const QString &error) {
Ui::show(Box<InformBox>(error));
if (what == ForwardPressedMessage || what == ForwardPressedLinkMessage) {
// We've already released the mouse button, so the forwarding is cancelled.
if (_hider) {
_hider->startHide();
noHider(_hider);
}
}
return false;
};
if (!peer->canWrite()) {
return finishWithError(lang(lng_forward_cant));
}
_history->cancelReply();
_toForward.clear();
auto toForward = SelectedItemSet();
if (what == ForwardSelectedMessages) {
if (_overview) {
_overview->fillSelectedItems(_toForward, false);
_overview->fillSelectedItems(toForward, false);
} else {
_history->fillSelectedItems(_toForward, false);
_history->fillSelectedItems(toForward, false);
}
} else {
HistoryItem *item = 0;
auto item = (HistoryItem*)nullptr;
if (what == ForwardContextMessage) {
item = App::contextItem();
} else if (what == ForwardPressedMessage) {
@ -529,9 +598,25 @@ bool MainWidget::onForward(const PeerId &peer, ForwardWhatMessages what) {
item = App::pressedLinkItem();
}
if (item && item->toHistoryMessage() && item->id > 0) {
_toForward.insert(item->id, item);
toForward.insert(item->id, item);
}
}
if (auto megagroup = peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_media() && HasMediaItems(toForward)) {
return finishWithError(lang(lng_restricted_send_media));
} else if (megagroup->restrictedRights().is_send_stickers() && HasStickerItems(toForward)) {
return finishWithError(lang(lng_restricted_send_stickers));
} else if (megagroup->restrictedRights().is_send_gifs() && HasGifItems(toForward)) {
return finishWithError(lang(lng_restricted_send_gifs));
} else if (megagroup->restrictedRights().is_send_games() && HasGameItems(toForward)) {
return finishWithError(lang(lng_restricted_send_inline));
} else if (megagroup->restrictedRights().is_send_inline() && HasInlineItems(toForward)) {
return finishWithError(lang(lng_restricted_send_inline));
}
}
_toForward = toForward;
_history->cancelReply();
updateForwardingItemRemovedSubscription();
updateForwardingTexts();
Ui::showPeerHistory(peer, ShowAtUnreadMsgId);
@ -777,23 +862,40 @@ void MainWidget::onUpdateMuted() {
App::updateMuted();
}
void MainWidget::onShareContact(const PeerId &peer, UserData *contact) {
_history->onShareContact(peer, contact);
void MainWidget::onShareContact(const PeerId &peerId, UserData *contact) {
_history->onShareContact(peerId, contact);
}
bool MainWidget::onSendPaths(const PeerId &peer) {
bool MainWidget::onSendPaths(const PeerId &peerId) {
Expects(peerId != 0);
auto peer = App::peer(peerId);
if (!peer->canWrite()) {
Ui::show(Box<InformBox>(lang(lng_forward_send_files_cant)));
return false;
} else if (auto megagroup = peer->asMegagroup()) {
if (megagroup->restrictedRights().is_send_media()) {
Ui::show(Box<InformBox>(lang(lng_restricted_send_media)));
return false;
}
}
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
return _history->confirmSendingFiles(cSendPaths());
}
void MainWidget::onFilesOrForwardDrop(const PeerId &peer, const QMimeData *data) {
void MainWidget::onFilesOrForwardDrop(const PeerId &peerId, const QMimeData *data) {
Expects(peerId != 0);
if (data->hasFormat(qsl("application/x-td-forward-selected"))) {
onForward(peer, ForwardSelectedMessages);
onForward(peerId, ForwardSelectedMessages);
} else if (data->hasFormat(qsl("application/x-td-forward-pressed-link"))) {
onForward(peer, ForwardPressedLinkMessage);
onForward(peerId, ForwardPressedLinkMessage);
} else if (data->hasFormat(qsl("application/x-td-forward-pressed"))) {
onForward(peer, ForwardPressedMessage);
onForward(peerId, ForwardPressedMessage);
} else {
auto peer = App::peer(peerId);
if (!peer->canWrite()) {
Ui::show(Box<InformBox>(lang(lng_forward_send_files_cant)));
return;
}
Ui::showPeerHistory(peer, ShowAtTheEndMsgId);
_history->confirmSendingFiles(data);
}
@ -1622,7 +1724,7 @@ void MainWidget::searchMessages(const QString &query, PeerData *inPeer) {
}
bool MainWidget::preloadOverview(PeerData *peer, MediaOverviewType type) {
auto filter = typeToMediaFilter(type);
auto filter = TypeToMediaFilter(type);
if (filter.type() == mtpc_inputMessagesFilterEmpty) {
return false;
}
@ -1695,7 +1797,7 @@ void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many
auto minId = history->overviewMinId(type);
auto limit = (many || history->overview[type].size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
auto filter = typeToMediaFilter(type);
auto filter = TypeToMediaFilter(type);
if (filter.type() == mtpc_inputMessagesFilterEmpty) {
return;
}