Disable selecting items with actions.

This commit is contained in:
John Preston 2021-11-05 21:37:01 +04:00
parent 487e8a9009
commit fd6751233e
11 changed files with 157 additions and 67 deletions

View File

@ -66,6 +66,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_poll.h"
#include "data/data_photo.h"
#include "data/data_photo_media.h"
#include "data/data_peer_values.h"
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_file_click_handler.h"
#include "data/data_file_origin.h"
@ -258,12 +260,61 @@ HistoryInner::HistoryInner(
) | rpl::start_with_next([=](int d) {
_scroll->scrollToY(_scroll->scrollTop() + d);
}, _scroll->lifetime());
setupSharingDisallowed();
}
Main::Session &HistoryInner::session() const {
return _controller->session();
}
void HistoryInner::setupSharingDisallowed() {
Expects(_peer != nullptr);
if (_peer->isUser()) {
_sharingDisallowed = false;
return;
}
const auto chat = _peer->asChat();
const auto channel = _peer->asChannel();
_sharingDisallowed = chat
? Data::PeerFlagValue(chat, ChatDataFlag::NoForwards)
: Data::PeerFlagValue(channel, ChannelDataFlag::NoForwards);
auto rights = chat
? chat->adminRightsValue()
: channel->adminRightsValue();
auto canDelete = std::move(
rights
) | rpl::map([=] {
return chat
? chat->canDeleteMessages()
: channel->canDeleteMessages();
});
rpl::combine(
_sharingDisallowed.value(),
std::move(canDelete)
) | rpl::filter([=](bool disallowed, bool canDelete) {
return hasSelectRestriction() && !getSelectedItems().empty();
}) | rpl::start_with_next([=] {
_widget->clearSelected();
if (_mouseAction == MouseAction::PrepareSelect) {
mouseActionCancel();
}
}, lifetime());
}
bool HistoryInner::hasSelectRestriction() const {
if (!_sharingDisallowed.current()) {
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 HistoryInner::messagesReceived(
PeerData *peer,
const QVector<MTPMessage> &messages) {
@ -1216,12 +1267,12 @@ void HistoryInner::mouseActionStart(const QPoint &screenPos, Qt::MouseButton but
_selected.emplace(_mouseActionItem, selStatus);
_mouseAction = MouseAction::Selecting;
repaintItem(_mouseActionItem);
} else {
} else if (!hasSelectRestriction()) {
_mouseAction = MouseAction::PrepareSelect;
}
}
}
} else if (!_pressWasInactive) {
} else if (!_pressWasInactive && !hasSelectRestriction()) {
_mouseAction = MouseAction::PrepareSelect; // start items select
}
}
@ -1250,7 +1301,8 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
}
const auto pressedHandler = ClickHandler::getPressed();
if (dynamic_cast<VoiceSeekClickHandler*>(pressedHandler.get())) {
if (dynamic_cast<VoiceSeekClickHandler*>(pressedHandler.get())
|| !_peer->allowsForwarding()) {
return nullptr;
}
@ -1281,7 +1333,6 @@ std::unique_ptr<QMimeData> HistoryInner::prepareDrag() {
}
}
}
auto urls = QList<QUrl>();
const auto selectedText = [&] {
if (uponSelected) {
@ -1737,6 +1788,29 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
};
const auto addSelectMessageAction = [&](
not_null<HistoryItem*> item,
bool asGroup = true) {
if (item->isRegular()
&& !item->isService()
&& !hasSelectRestriction()) {
const auto itemId = item->fullId();
_menu->addAction(tr::lng_context_select_msg(tr::now), [=] {
if (const auto item = session->data().message(itemId)) {
if (const auto view = item->mainView()) {
if (asGroup) {
changeSelectionAsGroup(&_selected, item, SelectAction::Select);
} else {
changeSelection(&_selected, item, SelectAction::Select);
}
repaintItem(item);
_widget->updateTopBarSelection();
}
}
});
}
};
if (hasWhoReadItem) {
const auto participantChosen = [=](uint64 id) {
controller->showPeerInfo(PeerId(id));
@ -1808,17 +1882,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
});
}
}
if (item->isRegular() && !item->isService()) {
_menu->addAction(tr::lng_context_select_msg(tr::now), [=] {
if (const auto item = session->data().message(itemId)) {
if (const auto view = item->mainView()) {
changeSelection(&_selected, item, SelectAction::Select);
repaintItem(item);
_widget->updateTopBarSelection();
}
}
});
}
addSelectMessageAction(item, false);
if (isUponSelected != -2 && blockSender) {
_menu->addAction(tr::lng_profile_block_user(tr::now), [=] {
blockSenderItem(itemId);
@ -1959,37 +2023,14 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
});
}
}
if (item->isRegular() && !item->isService()) {
_menu->addAction(tr::lng_context_select_msg(tr::now), [=] {
if (const auto item = session->data().message(itemId)) {
if (const auto view = item->mainView()) {
changeSelectionAsGroup(&_selected, item, SelectAction::Select);
repaintItem(view);
_widget->updateTopBarSelection();
}
}
});
}
addSelectMessageAction(item);
if (isUponSelected != -2 && canBlockSender) {
_menu->addAction(tr::lng_profile_block_user(tr::now), [=] {
blockSenderAsGroup(itemId);
});
}
} else {
if (App::mousedItem()
&& App::mousedItem()->data()->isRegular()
&& !App::mousedItem()->data()->isService()) {
const auto itemId = App::mousedItem()->data()->fullId();
_menu->addAction(tr::lng_context_select_msg(tr::now), [=] {
if (const auto item = session->data().message(itemId)) {
if (const auto view = item->mainView()) {
changeSelectionAsGroup(&_selected, item, SelectAction::Select);
repaintItem(item);
_widget->updateTopBarSelection();
}
}
});
}
} else if (App::mousedItem()) {
addSelectMessageAction(App::mousedItem()->data());
}
}
@ -2001,8 +2042,12 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
}
bool HistoryInner::hasCopyRestriction() const {
return !_peer->allowsForwarding();
}
bool HistoryInner::showCopyRestriction() {
if (_peer->allowsForwarding()) {
if (!hasCopyRestriction()) {
return false;
}
Ui::ShowMultilineToast({
@ -2817,18 +2862,6 @@ MessageIdsList HistoryInner::getSelectedItems() const {
return result;
}
void HistoryInner::selectItem(not_null<HistoryItem*> item) {
if (!_selected.empty() && _selected.cbegin()->second != FullSelection) {
_selected.clear();
} else if (_selected.size() == MaxSelectedItems
&& _selected.find(item) == _selected.cend()) {
return;
}
_selected.emplace(item, FullSelection);
_widget->updateTopBarSelection();
_widget->update();
}
void HistoryInner::onTouchSelect() {
_touchSelect = true;
mouseActionStart(_touchPos, Qt::LeftButton);
@ -3115,6 +3148,9 @@ void HistoryInner::mouseActionUpdate() {
void HistoryInner::updateDragSelection(Element *dragSelFrom, Element *dragSelTo, bool dragSelecting) {
if (_dragSelFrom == dragSelFrom && _dragSelTo == dragSelTo && _dragSelecting == dragSelecting) {
return;
} else if (dragSelFrom && hasSelectRestriction()) {
updateDragSelection(nullptr, nullptr, false);
return;
}
_dragSelFrom = dragSelFrom;
_dragSelTo = dragSelTo;
@ -3248,7 +3284,9 @@ void HistoryInner::notifyMigrateUpdated() {
}
void HistoryInner::applyDragSelection() {
applyDragSelection(&_selected);
if (!hasSelectRestriction()) {
applyDragSelection(&_selected);
}
}
bool HistoryInner::isSelected(

View File

@ -85,7 +85,6 @@ public:
HistoryView::TopBarWidget::SelectedState getSelectionState() const;
void clearSelected(bool onlyTextSelection = false);
MessageIdsList getSelectedItems() const;
void selectItem(not_null<HistoryItem*> item);
bool inSelectionMode() const;
bool elementIntersectsRange(
not_null<const Element*> view,
@ -342,7 +341,11 @@ private:
void blockSenderItem(FullMsgId itemId);
void blockSenderAsGroup(FullMsgId itemId);
void copySelectedText();
void setupSharingDisallowed();
[[nodiscard]] bool hasCopyRestriction() const;
bool showCopyRestriction();
[[nodiscard]] bool hasSelectRestriction() const;
// Does any of the shown histories has this flag set.
bool hasPendingResizedItems() const;
@ -416,6 +419,8 @@ private:
Ui::SelectScrollManager _selectScroll;
rpl::variable<bool> _sharingDisallowed = false;
Ui::TouchScrollState _touchScrollState = Ui::TouchScrollState::Manual;
bool _touchPrevPosValid = false;
bool _touchWaitingAcceleration = false;

View File

@ -811,7 +811,10 @@ bool AddSelectMessageAction(
const auto item = request.item;
if (request.overSelection && !request.selectedItems.empty()) {
return false;
} else if (!item || item->isLocal() || item->isService()) {
} else if (!item
|| item->isLocal()
|| item->isService()
|| list->hasSelectRestriction()) {
return false;
}
const auto owner = &item->history()->owner();

View File

@ -1076,7 +1076,9 @@ void ListWidget::cancelSelection() {
}
void ListWidget::selectItem(not_null<HistoryItem*> item) {
if (const auto view = viewForItem(item)) {
if (hasSelectRestriction()) {
return;
} else if (const auto view = viewForItem(item)) {
clearTextSelection();
changeSelection(
_selected,
@ -1087,7 +1089,9 @@ void ListWidget::selectItem(not_null<HistoryItem*> item) {
}
void ListWidget::selectItemAsGroup(not_null<HistoryItem*> item) {
if (const auto view = viewForItem(item)) {
if (hasSelectRestriction()) {
return;
} else if (const auto view = viewForItem(item)) {
clearTextSelection();
changeSelectionAsGroup(
_selected,
@ -1165,8 +1169,6 @@ bool ListWidget::isEmpty() const {
&& (_itemsHeight + _itemsRevealHeight == 0);
}
bool ListWidget::hasCopyRestriction() const {
return _delegate->listCopyRestrictionType() != CopyRestrictionType::None;
}
@ -1184,6 +1186,11 @@ bool ListWidget::showCopyRestriction() {
return true;
}
bool ListWidget::hasSelectRestriction() const {
return _delegate->listSelectRestrictionType()
!= CopyRestrictionType::None;
}
int ListWidget::itemMinimalHeight() const {
return st::msgMarginTopAttached
+ st::msgPhotoSize
@ -1751,7 +1758,9 @@ void ListWidget::paintEvent(QPaintEvent *e) {
}
void ListWidget::applyDragSelection() {
applyDragSelection(_selected);
if (!hasSelectRestriction()) {
applyDragSelection(_selected);
}
clearDragSelection();
pushSelectedItems();
}
@ -2080,7 +2089,9 @@ void ListWidget::leaveEventHook(QEvent *e) {
}
void ListWidget::updateDragSelection() {
if (!_overState.itemId || !_pressState.itemId) {
if (!_overState.itemId
|| !_pressState.itemId
|| hasSelectRestriction()) {
clearDragSelection();
return;
} else if (_items.empty() || !_overElement || !_selectEnabled) {
@ -2281,7 +2292,7 @@ void ListWidget::mouseActionStart(
} else if (hasSelectedItems()) {
if (overSelectedItems()) {
_mouseAction = MouseAction::PrepareDrag;
} else if (!_pressWasInactive) {
} else if (!_pressWasInactive && !hasSelectRestriction()) {
_mouseAction = MouseAction::PrepareSelect;
}
}
@ -2326,7 +2337,7 @@ void ListWidget::mouseActionStart(
_mouseTextSymbol,
_mouseTextSymbol));
_mouseAction = MouseAction::Selecting;
} else {
} else if (!hasSelectRestriction()) {
_mouseAction = MouseAction::PrepareSelect;
}
}
@ -2653,7 +2664,8 @@ std::unique_ptr<QMimeData> ListWidget::prepareDrag() {
return nullptr;
}
auto pressedHandler = ClickHandler::getPressed();
if (dynamic_cast<VoiceSeekClickHandler*>(pressedHandler.get())) {
if (dynamic_cast<VoiceSeekClickHandler*>(pressedHandler.get())
|| hasCopyRestriction()) {
return nullptr;
}
@ -3081,7 +3093,6 @@ void ConfirmSendNowSelectedItems(not_null<ListWidget*> widget) {
clearSelection);
}
CopyRestrictionType CopyRestrictionTypeFor(
not_null<PeerData*> peer) {
return peer->allowsForwarding()
@ -3091,4 +3102,18 @@ CopyRestrictionType CopyRestrictionTypeFor(
: CopyRestrictionType::Group;
}
CopyRestrictionType SelectRestrictionTypeFor(
not_null<PeerData*> peer) {
if (const auto chat = peer->asChat()) {
return chat->canDeleteMessages()
? CopyRestrictionType::None
: CopyRestrictionTypeFor(peer);
} else if (const auto channel = peer->asChannel()) {
return channel->canDeleteMessages()
? CopyRestrictionType::None
: CopyRestrictionTypeFor(peer);
}
return CopyRestrictionType::None;
}
} // namespace HistoryView

View File

@ -101,6 +101,7 @@ public:
virtual void listHandleViaClick(not_null<UserData*> bot) = 0;
virtual not_null<Ui::ChatTheme*> listChatTheme() = 0;
virtual CopyRestrictionType listCopyRestrictionType() = 0;
virtual CopyRestrictionType listSelectRestrictionType() = 0;
};
@ -213,6 +214,7 @@ public:
[[nodiscard]] bool hasCopyRestriction() const;
[[nodiscard]] bool showCopyRestriction();
[[nodiscard]] bool hasSelectRestriction() const;
// AbstractTooltipShower interface
QString tooltipText() const override;
@ -616,5 +618,7 @@ void ConfirmSendNowSelectedItems(not_null<ListWidget*> widget);
[[nodiscard]] CopyRestrictionType CopyRestrictionTypeFor(
not_null<PeerData*> peer);
[[nodiscard]] CopyRestrictionType SelectRestrictionTypeFor(
not_null<PeerData*> peer);
} // namespace HistoryView

View File

@ -680,6 +680,10 @@ CopyRestrictionType PinnedWidget::listCopyRestrictionType() {
return CopyRestrictionTypeFor(_history->peer);
}
CopyRestrictionType PinnedWidget::listSelectRestrictionType() {
return SelectRestrictionTypeFor(_history->peer);
}
void PinnedWidget::confirmDeleteSelected() {
ConfirmDeleteSelectedItems(_inner);
}

View File

@ -104,6 +104,7 @@ public:
void listHandleViaClick(not_null<UserData*> bot) override;
not_null<Ui::ChatTheme*> listChatTheme() override;
CopyRestrictionType listCopyRestrictionType() override;
CopyRestrictionType listSelectRestrictionType() override;
protected:
void resizeEvent(QResizeEvent *e) override;

View File

@ -1931,6 +1931,10 @@ CopyRestrictionType RepliesWidget::listCopyRestrictionType() {
return CopyRestrictionTypeFor(_history->peer);
}
CopyRestrictionType RepliesWidget::listSelectRestrictionType() {
return SelectRestrictionTypeFor(_history->peer);
}
void RepliesWidget::confirmDeleteSelected() {
ConfirmDeleteSelectedItems(_inner);
}

View File

@ -139,6 +139,7 @@ public:
void listHandleViaClick(not_null<UserData*> bot) override;
not_null<Ui::ChatTheme*> listChatTheme() override;
CopyRestrictionType listCopyRestrictionType() override;
CopyRestrictionType listSelectRestrictionType() override;
protected:
void resizeEvent(QResizeEvent *e) override;

View File

@ -1235,6 +1235,10 @@ CopyRestrictionType ScheduledWidget::listCopyRestrictionType() {
return CopyRestrictionType::None;
}
CopyRestrictionType ScheduledWidget::listSelectRestrictionType() {
return CopyRestrictionType::None;
}
void ScheduledWidget::confirmSendNowSelected() {
ConfirmSendNowSelectedItems(_inner);
}

View File

@ -120,6 +120,7 @@ public:
void listHandleViaClick(not_null<UserData*> bot) override;
not_null<Ui::ChatTheme*> listChatTheme() override;
CopyRestrictionType listCopyRestrictionType() override;
CopyRestrictionType listSelectRestrictionType() override;
protected:
void resizeEvent(QResizeEvent *e) override;