Disable copy to clipboard if noforwards.

This commit is contained in:
John Preston 2021-11-05 20:13:59 +04:00
parent 3a536c6f75
commit 487e8a9009
14 changed files with 166 additions and 46 deletions

View File

@ -148,8 +148,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_error_admin_limit" = "Sorry, you've reached the maximum number of admins for this group.";
"lng_error_admin_limit_channel" = "Sorry, you've reached the maximum number of admins for this channel.";
"lng_error_post_link_invalid" = "Unfortunately, you can't access this message. You are not a member of the chat where it was posted.";
"lng_error_noforwards_group" = "Sorry, forwarding is disabled from this group.";
"lng_error_noforwards_channel" = "Sorry, forwarding is disabled from this channel.";
"lng_error_noforwards_group" = "Sorry, forwarding from this group is disabled by admins.";
"lng_error_noforwards_channel" = "Sorry, forwarding from this channel is disabled by admins.";
"lng_error_nocopy_group" = "Sorry, copying from this group is disabled by admins.";
"lng_error_nocopy_channel" = "Sorry, copying from this channel is disabled by admins.";
"lng_sure_add_admin_invite" = "This user is not a member of this group. Add them to the group and promote them to admin?";
"lng_sure_add_admin_invite_channel" = "This user is not a subscriber of this channel. Add them to the channel and promote them to admin?";
"lng_sure_add_admin_unremove" = "This user is currently restricted or removed. Are you sure you want to promote them?";

View File

@ -25,7 +25,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/chat/chat_style.h"
#include "ui/widgets/popup_menu.h"
#include "ui/image/image.h"
#include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/text/text_options.h"
#include "ui/boxes/report_box.h"
@ -1494,7 +1494,8 @@ void HistoryInner::mouseActionFinish(
if (QGuiApplication::clipboard()->supportsSelection()
&& !_selected.empty()
&& _selected.cbegin()->second != FullSelection) {
&& _selected.cbegin()->second != FullSelection
&& _peer->allowsForwarding()) {
const auto [item, selection] = *_selected.cbegin();
if (const auto view = item->mainView()) {
TextUtilities::SetClipboardText(
@ -1673,7 +1674,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
};
const auto addPhotoActions = [&](not_null<PhotoData*> photo) {
const auto media = photo->activeMediaView();
if (!photo->isNull() && media && media->loaded()) {
if (!photo->isNull() && media && media->loaded() && _peer->allowsForwarding()) {
_menu->addAction(tr::lng_context_save_image(tr::now), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
savePhotoToFile(photo);
}));
@ -1753,7 +1754,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (lnkPhoto || lnkDocument) {
const auto item = _dragStateItem;
const auto itemId = item ? item->fullId() : FullMsgId();
if (isUponSelected > 0) {
if (isUponSelected > 0 && _peer->allowsForwarding()) {
_menu->addAction(
(isUponSelected > 1
? tr::lng_context_copy_selected_items(tr::now)
@ -1844,11 +1845,13 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto view = item ? item->mainView() : nullptr;
if (isUponSelected > 0) {
_menu->addAction(
((isUponSelected > 1)
? tr::lng_context_copy_selected_items(tr::now)
: tr::lng_context_copy_selected(tr::now)),
[=] { copySelectedText(); });
if (_peer->allowsForwarding()) {
_menu->addAction(
((isUponSelected > 1)
? tr::lng_context_copy_selected_items(tr::now)
: tr::lng_context_copy_selected(tr::now)),
[=] { copySelectedText(); });
}
addItemActions(item, item);
} else {
addItemActions(item, albumPartItem);
@ -1892,6 +1895,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
if (!item->isService()
&& view
&& !link
&& _peer->allowsForwarding()
&& (view->hasVisibleText() || mediaHasTextForCopy)) {
_menu->addAction(tr::lng_context_copy_text(tr::now), [=] {
copyContextText(itemId);
@ -1997,8 +2001,22 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
}
}
bool HistoryInner::showCopyRestriction() {
if (_peer->allowsForwarding()) {
return false;
}
Ui::ShowMultilineToast({
.text = { _peer->isBroadcast()
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now) },
});
return true;
}
void HistoryInner::copySelectedText() {
TextUtilities::SetClipboardText(getSelectedText());
if (!showCopyRestriction()) {
TextUtilities::SetClipboardText(getSelectedText());
}
}
void HistoryInner::savePhotoToFile(not_null<PhotoData*> photo) {
@ -2027,10 +2045,10 @@ void HistoryInner::copyContextImage(not_null<PhotoData*> photo) {
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
} else if (!showCopyRestriction()) {
const auto image = media->image(Data::PhotoSize::Large)->original();
QGuiApplication::clipboard()->setImage(image);
}
const auto image = media->image(Data::PhotoSize::Large)->original();
QGuiApplication::clipboard()->setImage(image);
}
void HistoryInner::showStickerPackInfo(not_null<DocumentData*> document) {
@ -2078,7 +2096,9 @@ void HistoryInner::saveContextGif(FullMsgId itemId) {
}
void HistoryInner::copyContextText(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) {
if (showCopyRestriction()) {
return;
} else if (const auto item = session().data().message(itemId)) {
if (const auto group = session().data().groups().find(item)) {
TextUtilities::SetClipboardText(HistoryGroupText(group));
} else {
@ -2174,7 +2194,8 @@ void HistoryInner::keyPressEvent(QKeyEvent *e) {
copySelectedText();
#ifdef Q_OS_MAC
} else if (e->key() == Qt::Key_E
&& e->modifiers().testFlag(Qt::ControlModifier)) {
&& e->modifiers().testFlag(Qt::ControlModifier)
&& !showCopyRestriction()) {
TextUtilities::SetClipboardText(getSelectedText(), QClipboard::FindBuffer);
#endif // Q_OS_MAC
} else if (e == QKeySequence::Delete) {

View File

@ -342,6 +342,7 @@ private:
void blockSenderItem(FullMsgId itemId);
void blockSenderAsGroup(FullMsgId itemId);
void copySelectedText();
bool showCopyRestriction();
// Does any of the shown histories has this flag set.
bool hasPendingResizedItems() const;

View File

@ -129,15 +129,19 @@ void AddPhotoActions(
not_null<Ui::PopupMenu*> menu,
not_null<PhotoData*> photo,
not_null<ListWidget*> list) {
menu->addAction(
tr::lng_context_save_image(tr::now),
App::LambdaDelayed(
st::defaultDropdownMenu.menu.ripple.hideDuration,
&photo->session(),
[=] { SavePhotoToFile(photo); }));
menu->addAction(tr::lng_context_copy_image(tr::now), [=] {
CopyImage(photo);
});
if (!list->hasCopyRestriction()) {
menu->addAction(
tr::lng_context_save_image(tr::now),
App::LambdaDelayed(
st::defaultDropdownMenu.menu.ripple.hideDuration,
&photo->session(),
[=] { SavePhotoToFile(photo); }));
menu->addAction(tr::lng_context_copy_image(tr::now), [=] {
if (!list->showCopyRestriction()) {
CopyImage(photo);
}
});
}
if (photo->hasAttachedStickers()) {
const auto controller = list->controller();
auto callback = [=] {
@ -903,12 +907,14 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
const auto hasSelection = !request.selectedItems.empty()
|| !request.selectedText.empty();
if (request.overSelection) {
if (request.overSelection && !list->hasCopyRestriction()) {
const auto text = request.selectedItems.empty()
? tr::lng_context_copy_selected(tr::now)
: tr::lng_context_copy_selected_items(tr::now);
result->addAction(text, [=] {
TextUtilities::SetClipboardText(list->getSelectedText());
if (!list->showCopyRestriction()) {
TextUtilities::SetClipboardText(list->getSelectedText());
}
});
}
@ -930,17 +936,21 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
view->data()->fullId(),
list);
}
if (!link && (view->hasVisibleText() || mediaHasTextForCopy)) {
if (!link
&& (view->hasVisibleText() || mediaHasTextForCopy)
&& !list->hasCopyRestriction()) {
const auto asGroup = (request.pointState != PointState::GroupPart);
result->addAction(tr::lng_context_copy_text(tr::now), [=] {
if (const auto item = owner->message(itemId)) {
if (asGroup) {
if (const auto group = owner->groups().find(item)) {
TextUtilities::SetClipboardText(HistoryGroupText(group));
return;
if (!list->showCopyRestriction()) {
if (const auto item = owner->message(itemId)) {
if (asGroup) {
if (const auto group = owner->groups().find(item)) {
TextUtilities::SetClipboardText(HistoryGroupText(group));
return;
}
}
TextUtilities::SetClipboardText(HistoryItemText(item));
}
TextUtilities::SetClipboardText(HistoryItemText(item));
}
});
}

View File

@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "ui/widgets/popup_menu.h"
#include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h"
#include "ui/inactive_press.h"
#include "ui/effects/path_shift_gradient.h"
#include "ui/chat/chat_theme.h"
@ -1164,6 +1165,25 @@ bool ListWidget::isEmpty() const {
&& (_itemsHeight + _itemsRevealHeight == 0);
}
bool ListWidget::hasCopyRestriction() const {
return _delegate->listCopyRestrictionType() != CopyRestrictionType::None;
}
bool ListWidget::showCopyRestriction() {
const auto type = _delegate->listCopyRestrictionType();
if (type == CopyRestrictionType::None) {
return false;
}
Ui::ShowMultilineToast({
.text = { (type == CopyRestrictionType::Channel)
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now) },
});
return true;
}
int ListWidget::itemMinimalHeight() const {
return st::msgMarginTopAttached
+ st::msgPhotoSize
@ -1892,11 +1912,13 @@ void ListWidget::keyPressEvent(QKeyEvent *e) {
_delegate->listCancelRequest();
}
} else if (e == QKeySequence::Copy
&& (hasSelectedText() || hasSelectedItems())) {
&& (hasSelectedText() || hasSelectedItems())
&& !showCopyRestriction()) {
TextUtilities::SetClipboardText(getSelectedText());
#ifdef Q_OS_MAC
} else if (e->key() == Qt::Key_E
&& e->modifiers().testFlag(Qt::ControlModifier)) {
&& e->modifiers().testFlag(Qt::ControlModifier)
&& !showCopyRestriction()) {
TextUtilities::SetClipboardText(getSelectedText(), QClipboard::FindBuffer);
#endif // Q_OS_MAC
} else if (e == QKeySequence::Delete) {
@ -2417,7 +2439,8 @@ void ListWidget::mouseActionFinish(
if (QGuiApplication::clipboard()->supportsSelection()
&& _selectedTextItem
&& _selectedTextRange.from != _selectedTextRange.to) {
&& _selectedTextRange.from != _selectedTextRange.to
&& !hasCopyRestriction()) {
if (const auto view = viewForItem(_selectedTextItem)) {
TextUtilities::SetClipboardText(
view->selectedText(_selectedTextRange),
@ -3058,4 +3081,14 @@ void ConfirmSendNowSelectedItems(not_null<ListWidget*> widget) {
clearSelection);
}
CopyRestrictionType CopyRestrictionTypeFor(
not_null<PeerData*> peer) {
return peer->allowsForwarding()
? CopyRestrictionType::None
: peer->isBroadcast()
? CopyRestrictionType::Channel
: CopyRestrictionType::Group;
}
} // namespace HistoryView

View File

@ -41,6 +41,12 @@ enum class CursorState : char;
enum class PointState : char;
enum class Context : char;
enum class CopyRestrictionType : char {
None,
Group,
Channel,
};
struct SelectedItem {
explicit SelectedItem(FullMsgId msgId) : msgId(msgId) {
}
@ -94,6 +100,7 @@ public:
const FullMsgId &context) = 0;
virtual void listHandleViaClick(not_null<UserData*> bot) = 0;
virtual not_null<Ui::ChatTheme*> listChatTheme() = 0;
virtual CopyRestrictionType listCopyRestrictionType() = 0;
};
@ -101,7 +108,6 @@ struct SelectionData {
bool canDelete = false;
bool canForward = false;
bool canSendNow = false;
};
using SelectedMap = base::flat_map<
@ -199,11 +205,14 @@ public:
void selectItem(not_null<HistoryItem*> item);
void selectItemAsGroup(not_null<HistoryItem*> item);
bool loadedAtTopKnown() const;
bool loadedAtTop() const;
bool loadedAtBottomKnown() const;
bool loadedAtBottom() const;
bool isEmpty() const;
[[nodiscard]] bool loadedAtTopKnown() const;
[[nodiscard]] bool loadedAtTop() const;
[[nodiscard]] bool loadedAtBottomKnown() const;
[[nodiscard]] bool loadedAtBottom() const;
[[nodiscard]] bool isEmpty() const;
[[nodiscard]] bool hasCopyRestriction() const;
[[nodiscard]] bool showCopyRestriction();
// AbstractTooltipShower interface
QString tooltipText() const override;
@ -605,4 +614,7 @@ void ConfirmDeleteSelectedItems(not_null<ListWidget*> widget);
void ConfirmForwardSelectedItems(not_null<ListWidget*> widget);
void ConfirmSendNowSelectedItems(not_null<ListWidget*> widget);
[[nodiscard]] CopyRestrictionType CopyRestrictionTypeFor(
not_null<PeerData*> peer);
} // namespace HistoryView

View File

@ -676,6 +676,10 @@ not_null<Ui::ChatTheme*> PinnedWidget::listChatTheme() {
return _theme.get();
}
CopyRestrictionType PinnedWidget::listCopyRestrictionType() {
return CopyRestrictionTypeFor(_history->peer);
}
void PinnedWidget::confirmDeleteSelected() {
ConfirmDeleteSelectedItems(_inner);
}

View File

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

View File

@ -1927,6 +1927,10 @@ not_null<Ui::ChatTheme*> RepliesWidget::listChatTheme() {
return _theme.get();
}
CopyRestrictionType RepliesWidget::listCopyRestrictionType() {
return CopyRestrictionTypeFor(_history->peer);
}
void RepliesWidget::confirmDeleteSelected() {
ConfirmDeleteSelectedItems(_inner);
}

View File

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

View File

@ -1231,6 +1231,10 @@ not_null<Ui::ChatTheme*> ScheduledWidget::listChatTheme() {
return _theme.get();
}
CopyRestrictionType ScheduledWidget::listCopyRestrictionType() {
return CopyRestrictionType::None;
}
void ScheduledWidget::confirmSendNowSelected() {
ConfirmSendNowSelectedItems(_inner);
}

View File

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

View File

@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/text/text_utilities.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/toast/toast.h"
#include "ui/toasts/common_toasts.h"
#include "ui/text/format_values.h"
#include "ui/item_text_options.h"
#include "ui/ui_utility.h"
@ -554,6 +555,23 @@ QSize OverlayWidget::flipSizeByRotation(QSize size) const {
return FlipSizeByRotation(size, _rotation);
}
bool OverlayWidget::hasCopyRestriction() const {
return _history && !_history->peer->allowsForwarding();
}
bool OverlayWidget::showCopyRestriction() {
if (!hasCopyRestriction()) {
return false;
}
Ui::ShowMultilineToast({
.parentOverride = _widget,
.text = { _history->peer->isBroadcast()
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now) },
});
return true;
}
bool OverlayWidget::videoShown() const {
return _streamed && !_streamed->instance.info().video.cover.isNull();
}
@ -891,8 +909,10 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
: tr::lng_context_show_in_folder(tr::now);
addAction(text, [=] { showInFolder(); });
}
if ((_document && documentContentShown()) || (_photo && _photoMedia->loaded())) {
addAction(tr::lng_mediaview_copy(tr::now), [=] { copyMedia(); });
if (!hasCopyRestriction()) {
if ((_document && documentContentShown()) || (_photo && _photoMedia->loaded())) {
addAction(tr::lng_mediaview_copy(tr::now), [=] { copyMedia(); });
}
}
if ((_photo && _photo->hasAttachedStickers())
|| (_document && _document->hasAttachedStickers())) {
@ -1756,6 +1776,9 @@ void OverlayWidget::showMediaOverview() {
}
void OverlayWidget::copyMedia() {
if (showCopyRestriction()) {
return;
}
_dropdown->hideAnimated(Ui::DropdownMenu::HideOption::IgnoreShow);
if (_document) {
QGuiApplication::clipboard()->setImage(transformedShownContent());

View File

@ -386,6 +386,9 @@ private:
void validatePhotoImage(Image *image, bool blurred);
void validatePhotoCurrentImage();
[[nodiscard]] bool hasCopyRestriction() const;
[[nodiscard]] bool showCopyRestriction();
[[nodiscard]] QSize flipSizeByRotation(QSize size) const;
void applyVideoSize();