Forbid saving / copying of extended media.

Fixes #25227.
This commit is contained in:
John Preston 2022-11-01 16:49:37 +04:00
parent bd8cdcb520
commit 7ec1af5e50
15 changed files with 122 additions and 22 deletions

View file

@ -2154,7 +2154,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
const auto addPhotoActions = [&](not_null<PhotoData*> photo, HistoryItem *item) {
const auto media = photo->activeMediaView();
const auto itemId = item ? item->fullId() : FullMsgId();
if (!photo->isNull() && media && media->loaded() && !hasCopyRestriction(item)) {
if (!photo->isNull() && media && media->loaded() && !hasCopyMediaRestriction(item)) {
_menu->addAction(tr::lng_context_save_image(tr::now), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
savePhotoToFile(photo);
}), &st::menuIconSaveImage);
@ -2194,7 +2194,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
openContextGif(itemId);
}, &st::menuIconShowInChat);
}
if (!hasCopyRestriction(item)) {
if (!hasCopyMediaRestriction(item)) {
_menu->addAction(tr::lng_context_save_gif(tr::now), [=] {
saveContextGif(itemId);
}, &st::menuIconGif);
@ -2205,7 +2205,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
showContextInFolder(document);
}, &st::menuIconShowInFolder);
}
if (item && !hasCopyRestriction(item)) {
if (item && !hasCopyMediaRestriction(item)) {
HistoryView::AddSaveSoundForNotifications(
_menu,
item,
@ -2373,7 +2373,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
Api::ToggleFavedSticker(controller, document, itemId);
}, isFaved ? &st::menuIconUnfave : &st::menuIconFave);
}
if (!hasCopyRestriction(item)) {
if (!hasCopyMediaRestriction(item)) {
_menu->addAction(tr::lng_context_save_image(tr::now), App::LambdaDelayed(st::defaultDropdownMenu.menu.ripple.hideDuration, this, [=] {
saveDocumentToFile(itemId, document);
}), &st::menuIconDownload);
@ -2533,6 +2533,11 @@ bool HistoryInner::hasCopyRestriction(HistoryItem *item) const {
return !_peer->allowsForwarding() || (item && item->forbidsForward());
}
bool HistoryInner::hasCopyMediaRestriction(
not_null<HistoryItem*> item) const {
return hasCopyRestriction(item) || item->forbidsSaving();
}
bool HistoryInner::showCopyRestriction(HistoryItem *item) {
if (!hasCopyRestriction(item)) {
return false;
@ -2546,6 +2551,19 @@ bool HistoryInner::showCopyRestriction(HistoryItem *item) {
return true;
}
bool HistoryInner::showCopyMediaRestriction(not_null<HistoryItem*> item) {
if (!hasCopyMediaRestriction(item)) {
return false;
}
Ui::ShowMultilineToast({
.parentOverride = Window::Show(_controller).toastParent(),
.text = { _peer->isBroadcast()
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now) },
});
return true;
}
bool HistoryInner::hasCopyRestrictionForSelected() const {
if (hasCopyRestriction()) {
return true;
@ -2601,7 +2619,7 @@ void HistoryInner::copyContextImage(
const auto media = photo->activeMediaView();
if (photo->isNull() || !media || !media->loaded()) {
return;
} else if (!showCopyRestriction(item)) {
} else if (!showCopyMediaRestriction(item)) {
const auto image = media->image(Data::PhotoSize::Large)->original();
QGuiApplication::clipboard()->setImage(image);
}
@ -2643,7 +2661,7 @@ void HistoryInner::openContextGif(FullMsgId itemId) {
void HistoryInner::saveContextGif(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) {
if (!hasCopyRestriction(item)) {
if (!hasCopyMediaRestriction(item)) {
if (const auto media = item->media()) {
if (const auto document = media->document()) {
Api::ToggleSavedGif(

View file

@ -403,7 +403,10 @@ private:
void setupSharingDisallowed();
[[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const;
[[nodiscard]] bool hasCopyMediaRestriction(
not_null<HistoryItem*> item) const;
bool showCopyRestriction(HistoryItem *item = nullptr);
bool showCopyMediaRestriction(not_null<HistoryItem*> item);
[[nodiscard]] bool hasCopyRestrictionForSelected() const;
bool showCopyRestrictionForSelected();
[[nodiscard]] bool hasSelectRestriction() const;

View file

@ -833,6 +833,15 @@ bool HistoryItem::forbidsForward() const {
return (_flags & MessageFlag::NoForwards);
}
bool HistoryItem::forbidsSaving() const {
if (forbidsForward()) {
return true;
} else if (const auto invoice = _media ? _media->invoice() : nullptr) {
return (invoice->extendedMedia != nullptr);
}
return false;
}
bool HistoryItem::canDelete() const {
if (isSponsored()) {
return false;

View file

@ -345,6 +345,7 @@ public:
[[nodiscard]] bool canBeEdited() const;
[[nodiscard]] bool canStopPoll() const;
[[nodiscard]] bool forbidsForward() const;
[[nodiscard]] bool forbidsSaving() const;
[[nodiscard]] virtual bool allowsSendNow() const;
[[nodiscard]] virtual bool allowsForward() const;
[[nodiscard]] virtual bool allowsEdit(TimeId now) const;

View file

@ -147,7 +147,7 @@ void AddPhotoActions(
HistoryItem *item,
not_null<ListWidget*> list) {
const auto contextId = item ? item->fullId() : FullMsgId();
if (!list->hasCopyRestriction(item)) {
if (!list->hasCopyMediaRestriction(item)) {
menu->addAction(
tr::lng_context_save_image(tr::now),
App::LambdaDelayed(
@ -157,7 +157,7 @@ void AddPhotoActions(
&st::menuIconSaveImage);
menu->addAction(tr::lng_context_copy_image(tr::now), [=] {
const auto item = photo->owner().message(contextId);
if (!list->showCopyRestriction(item)) {
if (!list->showCopyMediaRestriction(item)) {
CopyImage(photo);
}
}, &st::menuIconCopy);
@ -214,7 +214,7 @@ void AddSaveDocumentAction(
HistoryItem *item,
not_null<DocumentData*> document,
not_null<ListWidget*> list) {
if (list->hasCopyRestriction(item)) {
if (list->hasCopyMediaRestriction(item)) {
return;
}
const auto origin = item ? item->fullId() : FullMsgId();
@ -269,7 +269,7 @@ void AddDocumentActions(
}
}, &st::menuIconShowInChat);
}
if (!list->hasCopyRestriction(item)) {
if (!list->hasCopyMediaRestriction(item)) {
menu->addAction(tr::lng_context_save_gif(tr::now), [=] {
SaveGif(list->controller(), contextId);
}, &st::menuIconGif);
@ -309,7 +309,7 @@ void AddDocumentActions(
std::move(callback),
&st::menuIconStickers);
}
if (item && !list->hasCopyRestriction(item)) {
if (item && !list->hasCopyMediaRestriction(item)) {
const auto controller = list->controller();
AddSaveSoundForNotifications(menu, item, document, controller);
}

View file

@ -1335,6 +1335,11 @@ bool ListWidget::hasCopyRestriction(HistoryItem *item) const {
!= CopyRestrictionType::None;
}
bool ListWidget::hasCopyMediaRestriction(not_null<HistoryItem*> item) const {
return _delegate->listCopyMediaRestrictionType(item)
!= CopyRestrictionType::None;
}
bool ListWidget::showCopyRestriction(HistoryItem *item) {
const auto type = _delegate->listCopyRestrictionType(item);
if (type == CopyRestrictionType::None) {
@ -1349,6 +1354,20 @@ bool ListWidget::showCopyRestriction(HistoryItem *item) {
return true;
}
bool ListWidget::showCopyMediaRestriction(not_null<HistoryItem*> item) {
const auto type = _delegate->listCopyMediaRestrictionType(item);
if (type == CopyRestrictionType::None) {
return false;
}
Ui::ShowMultilineToast({
.parentOverride = Window::Show(_controller).toastParent(),
.text = { (type == CopyRestrictionType::Channel)
? tr::lng_error_nocopy_channel(tr::now)
: tr::lng_error_nocopy_group(tr::now) },
});
return true;
}
bool ListWidget::hasCopyRestrictionForSelected() const {
if (hasCopyRestriction()) {
return true;
@ -3867,6 +3886,20 @@ CopyRestrictionType CopyRestrictionTypeFor(
: CopyRestrictionType::Group;
}
CopyRestrictionType CopyMediaRestrictionTypeFor(
not_null<PeerData*> peer,
not_null<HistoryItem*> item) {
if (const auto all = CopyRestrictionTypeFor(peer, item)
; all != CopyRestrictionType::None) {
return all;
}
return !item->forbidsSaving()
? CopyRestrictionType::None
: peer->isBroadcast()
? CopyRestrictionType::Channel
: CopyRestrictionType::Group;
}
CopyRestrictionType SelectRestrictionTypeFor(
not_null<PeerData*> peer) {
if (const auto chat = peer->asChat()) {

View file

@ -125,6 +125,8 @@ public:
CopyRestrictionType listCopyRestrictionType() {
return listCopyRestrictionType(nullptr);
}
virtual CopyRestrictionType listCopyMediaRestrictionType(
not_null<HistoryItem*> item) = 0;
virtual CopyRestrictionType listSelectRestrictionType() = 0;
virtual auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> = 0;
@ -244,7 +246,10 @@ public:
[[nodiscard]] bool isEmpty() const;
[[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const;
[[nodiscard]] bool hasCopyMediaRestriction(
not_null<HistoryItem*> item) const;
[[nodiscard]] bool showCopyRestriction(HistoryItem *item = nullptr);
[[nodiscard]] bool showCopyMediaRestriction(not_null<HistoryItem*> item);
[[nodiscard]] bool hasCopyRestrictionForSelected() const;
[[nodiscard]] bool showCopyRestrictionForSelected();
[[nodiscard]] bool hasSelectRestriction() const;
@ -733,6 +738,9 @@ void ConfirmSendNowSelectedItems(not_null<ListWidget*> widget);
[[nodiscard]] CopyRestrictionType CopyRestrictionTypeFor(
not_null<PeerData*> peer,
HistoryItem *item = nullptr);
[[nodiscard]] CopyRestrictionType CopyMediaRestrictionTypeFor(
not_null<PeerData*> peer,
not_null<HistoryItem*> item);
[[nodiscard]] CopyRestrictionType SelectRestrictionTypeFor(
not_null<PeerData*> peer);

View file

@ -583,6 +583,11 @@ CopyRestrictionType PinnedWidget::listCopyRestrictionType(
return CopyRestrictionTypeFor(_history->peer, item);
}
CopyRestrictionType PinnedWidget::listCopyMediaRestrictionType(
not_null<HistoryItem*> item) {
return CopyMediaRestrictionTypeFor(_history->peer, item);
}
CopyRestrictionType PinnedWidget::listSelectRestrictionType() {
return SelectRestrictionTypeFor(_history->peer);
}

View file

@ -110,6 +110,8 @@ public:
void listHandleViaClick(not_null<UserData*> bot) override;
not_null<Ui::ChatTheme*> listChatTheme() override;
CopyRestrictionType listCopyRestrictionType(HistoryItem *item) override;
CopyRestrictionType listCopyMediaRestrictionType(
not_null<HistoryItem*> item) override;
CopyRestrictionType listSelectRestrictionType() override;
auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> override;

View file

@ -2436,6 +2436,11 @@ CopyRestrictionType RepliesWidget::listCopyRestrictionType(
return CopyRestrictionTypeFor(_history->peer, item);
}
CopyRestrictionType RepliesWidget::listCopyMediaRestrictionType(
not_null<HistoryItem*> item) {
return CopyMediaRestrictionTypeFor(_history->peer, item);
}
CopyRestrictionType RepliesWidget::listSelectRestrictionType() {
return SelectRestrictionTypeFor(_history->peer);
}

View file

@ -154,6 +154,8 @@ public:
void listHandleViaClick(not_null<UserData*> bot) override;
not_null<Ui::ChatTheme*> listChatTheme() override;
CopyRestrictionType listCopyRestrictionType(HistoryItem *item) override;
CopyRestrictionType listCopyMediaRestrictionType(
not_null<HistoryItem*> item) override;
CopyRestrictionType listSelectRestrictionType() override;
auto listAllowedReactionsValue()
->rpl::producer<Data::AllowedReactions> override;

View file

@ -1250,6 +1250,18 @@ CopyRestrictionType ScheduledWidget::listCopyRestrictionType(
return CopyRestrictionType::None;
}
CopyRestrictionType ScheduledWidget::listCopyMediaRestrictionType(
not_null<HistoryItem*> item) {
if (const auto media = item->media()) {
if (const auto invoice = media->invoice()) {
if (invoice->extendedMedia) {
return CopyMediaRestrictionTypeFor(_history->peer, item);
}
}
}
return CopyRestrictionType::None;
}
CopyRestrictionType ScheduledWidget::listSelectRestrictionType() {
return CopyRestrictionType::None;
}

View file

@ -133,6 +133,8 @@ public:
void listHandleViaClick(not_null<UserData*> bot) override;
not_null<Ui::ChatTheme*> listChatTheme() override;
CopyRestrictionType listCopyRestrictionType(HistoryItem *item) override;
CopyRestrictionType listCopyMediaRestrictionType(
not_null<HistoryItem*> item) override;
CopyRestrictionType listSelectRestrictionType() override;
auto listAllowedReactionsValue()
-> rpl::producer<Data::AllowedReactions> override;

View file

@ -563,13 +563,13 @@ QSize OverlayWidget::flipSizeByRotation(QSize size) const {
return FlipSizeByRotation(size, _rotation);
}
bool OverlayWidget::hasCopyRestriction() const {
bool OverlayWidget::hasCopyMediaRestriction() const {
return (_history && !_history->peer->allowsForwarding())
|| (_message && _message->forbidsForward());
|| (_message && _message->forbidsSaving());
}
bool OverlayWidget::showCopyRestriction() {
if (!hasCopyRestriction()) {
bool OverlayWidget::showCopyMediaRestriction() {
if (!hasCopyMediaRestriction()) {
return false;
}
Ui::ShowMultilineToast({
@ -739,7 +739,7 @@ void OverlayWidget::refreshNavVisibility() {
}
bool OverlayWidget::contentCanBeSaved() const {
if (hasCopyRestriction()) {
if (hasCopyMediaRestriction()) {
return false;
} else if (_photo) {
return _photo->hasVideo() || _photoMedia->loaded();
@ -932,7 +932,7 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
[=] { showInFolder(); },
&st::mediaMenuIconShowInFolder);
}
if (!hasCopyRestriction()) {
if (!hasCopyMediaRestriction()) {
if ((_document && documentContentShown()) || (_photo && _photoMedia->loaded())) {
addAction(
tr::lng_mediaview_copy(tr::now),
@ -976,7 +976,7 @@ void OverlayWidget::fillContextMenuActions(const MenuCallback &addAction) {
[=] { deleteMedia(); },
&st::mediaMenuIconDelete);
}
if (!hasCopyRestriction()) {
if (!hasCopyMediaRestriction()) {
addAction(
tr::lng_mediaview_save_as(tr::now),
[=] { saveAs(); },
@ -1602,7 +1602,7 @@ void OverlayWidget::notifyFileDialogShown(bool shown) {
}
void OverlayWidget::saveAs() {
if (showCopyRestriction()) {
if (showCopyMediaRestriction()) {
return;
}
QString file;
@ -1938,7 +1938,7 @@ void OverlayWidget::showMediaOverview() {
}
void OverlayWidget::copyMedia() {
if (showCopyRestriction()) {
if (showCopyMediaRestriction()) {
return;
}
_dropdown->hideAnimated(Ui::DropdownMenu::HideOption::IgnoreShow);

View file

@ -409,8 +409,8 @@ private:
void validatePhotoImage(Image *image, bool blurred);
void validatePhotoCurrentImage();
[[nodiscard]] bool hasCopyRestriction() const;
[[nodiscard]] bool showCopyRestriction();
[[nodiscard]] bool hasCopyMediaRestriction() const;
[[nodiscard]] bool showCopyMediaRestriction();
[[nodiscard]] QSize flipSizeByRotation(QSize size) const;