From 5309af5d560063b97ad24db91149f5ca682cee1e Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 30 Nov 2021 16:26:47 +0400 Subject: [PATCH] Restrict shared media selection in noforward chats. --- Telegram/SourceFiles/info/info_top_bar.cpp | 20 ++++- Telegram/SourceFiles/info/info_top_bar.h | 2 + .../info/media/info_media_list_widget.cpp | 87 +++++++++++++++---- .../info/media/info_media_list_widget.h | 3 + 4 files changed, 92 insertions(+), 20 deletions(-) diff --git a/Telegram/SourceFiles/info/info_top_bar.cpp b/Telegram/SourceFiles/info/info_top_bar.cpp index f7e01b8076..79186333ed 100644 --- a/Telegram/SourceFiles/info/info_top_bar.cpp +++ b/Telegram/SourceFiles/info/info_top_bar.cpp @@ -341,8 +341,10 @@ void TopBar::updateSelectionControlsGeometry(int newWidth) { _delete->moveToRight(right, 0, newWidth); right += _delete->width(); } - _forward->moveToRight(right, 0, newWidth); - right += _forward->width(); + if (_canForward) { + _forward->moveToRight(right, 0, newWidth); + right += _forward->width(); + } auto left = 0; _cancelSelection->moveToLeft(left, 0); @@ -411,6 +413,7 @@ void TopBar::setSelectedItems(SelectedItems &&items) { SelectedItems TopBar::takeSelectedItems() { _canDelete = false; + _canForward = false; return std::move(_selectedItems); } @@ -419,11 +422,13 @@ rpl::producer<> TopBar::cancelSelectionRequests() const { } void TopBar::updateSelectionState() { - Expects(_selectionText && _delete); + Expects(_selectionText && _delete && _forward); _canDelete = computeCanDelete(); + _canForward = computeCanForward(); _selectionText->entity()->setValue(generateSelectedText()); _delete->toggle(_canDelete, anim::type::instant); + _forward->toggle(_canForward, anim::type::instant); updateSelectionControlsGeometry(width()); } @@ -437,6 +442,7 @@ void TopBar::createSelectionControls() { return created; }; _canDelete = computeCanDelete(); + _canForward = computeCanForward(); _cancelSelection = wrap(Ui::CreateChild>( this, object_ptr(this, _st.mediaCancel), @@ -461,8 +467,12 @@ void TopBar::createSelectionControls() { this, object_ptr(this, _st.mediaForward), st::infoTopBarScale)); + registerToggleControlCallback( + _forward.data(), + [this] { return selectionMode() && _canForward; }); _forward->setDuration(st::infoTopBarDuration); _forward->entity()->addClickHandler([this] { performForward(); }); + _forward->entity()->setVisible(_canForward); _delete = wrap(Ui::CreateChild>( this, object_ptr(this, _st.mediaDelete), @@ -481,6 +491,10 @@ bool TopBar::computeCanDelete() const { return ranges::all_of(_selectedItems.list, &SelectedItem::canDelete); } +bool TopBar::computeCanForward() const { + return ranges::all_of(_selectedItems.list, &SelectedItem::canForward); +} + Ui::StringWithNumbers TopBar::generateSelectedText() const { using Type = Storage::SharedMediaType; const auto phrase = [&] { diff --git a/Telegram/SourceFiles/info/info_top_bar.h b/Telegram/SourceFiles/info/info_top_bar.h index d44a16f630..4d1c7e823b 100644 --- a/Telegram/SourceFiles/info/info_top_bar.h +++ b/Telegram/SourceFiles/info/info_top_bar.h @@ -111,6 +111,7 @@ private: bool searchMode() const; Ui::StringWithNumbers generateSelectedText() const; [[nodiscard]] bool computeCanDelete() const; + [[nodiscard]] bool computeCanForward() const; void updateSelectionState(); void createSelectionControls(); void clearSelectionControls(); @@ -153,6 +154,7 @@ private: SelectedItems _selectedItems; bool _canDelete = false; + bool _canForward = false; QPointer> _cancelSelection; QPointer> _selectionText; QPointer> _forward; diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 7f3d46cee5..5940ca79a3 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -13,6 +13,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "layout/layout_selection.h" #include "data/data_media_types.h" #include "data/data_photo.h" +#include "data/data_chat.h" +#include "data/data_channel.h" +#include "data/data_peer_values.h" #include "data/data_document.h" #include "data/data_session.h" #include "data/data_file_click_handler.h" @@ -731,9 +734,44 @@ void ListWidget::start() { }, lifetime()); _controller->mediaSourceQueryValue( - ) | rpl::start_with_next([this]{ + ) | rpl::start_with_next([this] { restart(); }, lifetime()); + + setupSelectRestriction(); +} + +void ListWidget::setupSelectRestriction() { + const auto chat = _peer->asChat(); + const auto channel = _peer->asChannel(); + auto noForwards = chat + ? Data::PeerFlagValue(chat, ChatDataFlag::NoForwards) + : Data::PeerFlagValue( + channel, + ChannelDataFlag::NoForwards + ) | rpl::type_erased(); + + auto rights = chat + ? chat->adminRightsValue() + : channel->adminRightsValue(); + auto canDelete = std::move( + rights + ) | rpl::map([=] { + return chat + ? chat->canDeleteMessages() + : channel->canDeleteMessages(); + }); + rpl::combine( + std::move(noForwards), + std::move(canDelete) + ) | rpl::filter([=] { + return hasSelectRestriction() && hasSelectedItems(); + }) | rpl::start_with_next([=] { + clearSelected(); + if (_mouseAction == MouseAction::PrepareSelect) { + mouseActionCancel(); + } + }, lifetime()); } rpl::producer ListWidget::scrollToRequests() const { @@ -1656,18 +1694,20 @@ void ListWidget::showContextMenu( [=] { _contextMenu = nullptr; })); } } - _contextMenu->addAction( - tr::lng_context_select_msg(tr::now), - crl::guard(this, [this, universalId] { - if (hasSelectedText()) { - clearSelected(); - } else if (_selected.size() == MaxSelectedItems) { - return; - } else if (_selected.empty()) { - update(); - } - applyItemSelection(universalId, FullSelection); - })); + if (!hasSelectRestriction()) { + _contextMenu->addAction( + tr::lng_context_select_msg(tr::now), + crl::guard(this, [this, universalId] { + if (hasSelectedText()) { + clearSelected(); + } else if (_selected.size() == MaxSelectedItems) { + return; + } else if (_selected.empty()) { + update(); + } + applyItemSelection(universalId, FullSelection); + })); + } } _contextMenu->setDestroyedCallback(crl::guard( @@ -1739,6 +1779,17 @@ DeleteMessagesBox *ListWidget::deleteItems(MessageIdsList &&items) { return nullptr; } +bool ListWidget::hasSelectRestriction() const { + if (_peer->allowsForwarding()) { + return false; + } else if (const auto chat = _peer->asChat()) { + return !chat->canDeleteMessages(); + } else if (const auto channel = _peer->asChannel()) { + return !channel->canDeleteMessages(); + } + return true; +} + void ListWidget::setActionBoxWeak(QPointer box) { if ((_actionBoxWeak = box)) { _actionBoxWeakLifetime = _actionBoxWeak->alive( @@ -2047,7 +2098,7 @@ void ListWidget::updateDragSelection() { if (swapStates) { std::swap(fromState, tillState); } - if (!fromState.itemId || !tillState.itemId) { + if (!fromState.itemId || !tillState.itemId || hasSelectRestriction()) { clearDragSelection(); return; } @@ -2183,12 +2234,12 @@ void ListWidget::mouseActionStart( applyItemSelection(_pressState.itemId, selStatus); _mouseAction = MouseAction::Selecting; repaintItem(pressLayout); - } else { + } else if (!hasSelectRestriction()) { _mouseAction = MouseAction::PrepareSelect; } } } - } else if (!_pressWasInactive) { + } else if (!_pressWasInactive && !hasSelectRestriction()) { _mouseAction = MouseAction::PrepareSelect; // start items select } } @@ -2365,7 +2416,9 @@ void ListWidget::mouseActionFinish( } void ListWidget::applyDragSelection() { - applyDragSelection(_selected); + if (!hasSelectRestriction()) { + applyDragSelection(_selected); + } clearDragSelection(); pushSelectedItems(); } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index 4c4e39ceca..19d39d6ff5 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -176,6 +176,9 @@ private: int recountHeight(); void refreshHeight(); + void setupSelectRestriction(); + [[nodiscard]] bool hasSelectRestriction() const; + QMargins padding() const; bool isMyItem(not_null item) const; bool isItemLayout(