diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt
index 9a2a48ea9e..513390ae49 100644
--- a/Telegram/CMakeLists.txt
+++ b/Telegram/CMakeLists.txt
@@ -858,6 +858,8 @@ PRIVATE
history/view/media/history_view_media_spoiler.h
history/view/media/history_view_media_unwrapped.cpp
history/view/media/history_view_media_unwrapped.h
+ history/view/media/history_view_no_forwards_request.cpp
+ history/view/media/history_view_no_forwards_request.h
history/view/media/history_view_photo.cpp
history/view/media/history_view_photo.h
history/view/media/history_view_poll.cpp
diff --git a/Telegram/Resources/animations/stop.tgs b/Telegram/Resources/animations/stop.tgs
new file mode 100644
index 0000000000..70ace96393
Binary files /dev/null and b/Telegram/Resources/animations/stop.tgs differ
diff --git a/Telegram/Resources/icons/menu/download_off.svg b/Telegram/Resources/icons/menu/download_off.svg
new file mode 100644
index 0000000000..bac54d5525
--- /dev/null
+++ b/Telegram/Resources/icons/menu/download_off.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/Telegram/Resources/icons/menu/share_off.svg b/Telegram/Resources/icons/menu/share_off.svg
new file mode 100644
index 0000000000..96d32e3bda
--- /dev/null
+++ b/Telegram/Resources/icons/menu/share_off.svg
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/Telegram/Resources/icons/menu/share_on.svg b/Telegram/Resources/icons/menu/share_on.svg
new file mode 100644
index 0000000000..bb8edfe992
--- /dev/null
+++ b/Telegram/Resources/icons/menu/share_on.svg
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings
index 179518600c..f7cff57c6f 100644
--- a/Telegram/Resources/langs/lang.strings
+++ b/Telegram/Resources/langs/lang.strings
@@ -1898,6 +1898,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_peer_no_forwards_about" = "Members won't be able to copy, save or forward content from this group.";
"lng_manage_peer_no_forwards_about_channel" = "Subscribers won't be able to copy, save or forward content from this channel.";
+"lng_disable_sharing" = "Disable Sharing";
+"lng_enable_sharing" = "Enable Sharing";
+"lng_disable_sharing_title" = "Disable Sharing";
+"lng_disable_sharing_no_forwarding" = "No Forwarding";
+"lng_disable_sharing_no_forwarding_about" = "Disable message forwarding to other chats.";
+"lng_disable_sharing_no_saving" = "No Saving";
+"lng_disable_sharing_no_saving_about" = "Disable copying texts and saving photos and videos to gallery.";
+"lng_disable_sharing_unlock" = "Unlock with Telegram Premium";
+"lng_disable_sharing_button" = "Disable Sharing";
+"lng_disable_sharing_toast" = "Sharing disabled for this chat.";
+"lng_enable_sharing_toast" = "Sharing enabled for this chat.";
+
+"lng_action_no_forwards_you_disabled" = "You disabled sharing in this chat.";
+"lng_action_no_forwards_you_enabled" = "You enabled sharing in this chat.";
+"lng_action_no_forwards_disabled" = "{from} disabled sharing in this chat.";
+"lng_action_no_forwards_enabled" = "{from} enabled sharing in this chat.";
+"lng_action_no_forwards_still_disabled" = "Sharing in this chat is still disabled.";
+"lng_action_no_forwards_request" = "{from} would like to enable sharing in this chat, which includes:";
+"lng_action_no_forwards_request_you" = "You requested to enable sharing in this chat, which includes:";
+"lng_action_no_forwards_feature_forwarding" = "Forwarding messages";
+"lng_action_no_forwards_feature_saving" = "Saving photos and videos";
+"lng_action_no_forwards_feature_copying" = "Copying messages";
+"lng_action_no_forwards_accept" = "Accept";
+"lng_action_no_forwards_reject" = "Reject";
+
"lng_manage_peer_bot_public_link" = "Public Link";
"lng_manage_peer_bot_public_links" = "Public Links";
"lng_manage_peer_bot_balance" = "Balance";
@@ -5005,7 +5030,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_noforwards_info_channel" = "Copying and forwarding is not allowed in this channel.";
"lng_context_noforwards_info_group" = "Copying and forwarding is not allowed in this group.";
"lng_context_noforwards_info_bot" = "Copying and forwarding is not allowed from this bot.";
-"lng_context_noforwards_info_user" = "Copying and forwarding is not allowed in this chat.";
+"lng_context_noforwards_info_his" = "{user} disabled copying and forwarding in this chat.";
+"lng_context_noforwards_info_mine" = "You disabled copying and forwarding in this chat.";
"lng_context_spoiler_effect" = "Hide with Spoiler";
"lng_context_disable_spoiler" = "Remove Spoiler";
diff --git a/Telegram/Resources/qrc/telegram/animations.qrc b/Telegram/Resources/qrc/telegram/animations.qrc
index 1ab7e76e83..989baedd1a 100644
--- a/Telegram/Resources/qrc/telegram/animations.qrc
+++ b/Telegram/Resources/qrc/telegram/animations.qrc
@@ -56,6 +56,7 @@
../../animations/ban.tgs
../../animations/cocoon.tgs
../../animations/craft_failed.tgs
+ ../../animations/stop.tgs
../../animations/profile/profile_muting.tgs
../../animations/profile/profile_unmuting.tgs
diff --git a/Telegram/SourceFiles/api/api_suggest_post.cpp b/Telegram/SourceFiles/api/api_suggest_post.cpp
index 7c5a31b314..073d9dd9cc 100644
--- a/Telegram/SourceFiles/api/api_suggest_post.cpp
+++ b/Telegram/SourceFiles/api/api_suggest_post.cpp
@@ -520,6 +520,40 @@ void ConfirmGiftSaleDecline(
ShowGiftSaleRejectBox(window, item, suggestion);
}
+void RespondToNoForwardsRequest(
+ not_null controller,
+ not_null item,
+ not_null request,
+ bool accept) {
+ if (request->requestId) {
+ return;
+ }
+ const auto id = item->fullId();
+ const auto session = &item->history()->session();
+ const auto peer = item->history()->peer;
+ const auto msgId = item->id;
+ const auto finish = [=] {
+ if (const auto item = session->data().message(id)) {
+ if (const auto r = item->Get()) {
+ r->requestId = 0;
+ }
+ }
+ };
+ using Flag = MTPmessages_ToggleNoForwards::Flag;
+ request->requestId = session->api().request(MTPmessages_ToggleNoForwards(
+ MTP_flags(Flag::f_request_msg_id),
+ peer->input(),
+ MTP_bool(!accept),
+ MTP_int(msgId)
+ )).done([=](const MTPUpdates &result) {
+ session->api().applyUpdates(result);
+ finish();
+ }).fail([=](const MTP::Error &error) {
+ controller->showToast(error.type());
+ finish();
+ }).send();
+}
+
} // namespace
std::shared_ptr AcceptClickHandler(
@@ -538,7 +572,11 @@ std::shared_ptr AcceptClickHandler(
}
const auto show = controller->uiShow();
const auto suggestion = item->Get();
- if (!suggestion) {
+ const auto nfRequest = item->Get();
+ if (!suggestion && !nfRequest) {
+ return;
+ } else if (nfRequest) {
+ RespondToNoForwardsRequest(controller, item, nfRequest, true);
return;
} else if (suggestion->gift) {
ConfirmGiftSaleAccept(controller, item, suggestion);
@@ -564,6 +602,11 @@ std::shared_ptr DeclineClickHandler(
if (!item) {
return;
}
+ const auto nfRequest = item->Get();
+ if (nfRequest) {
+ RespondToNoForwardsRequest(controller, item, nfRequest, false);
+ return;
+ }
const auto suggestion = item->Get();
if (suggestion && suggestion->gift) {
ConfirmGiftSaleDecline(controller, item, suggestion);
diff --git a/Telegram/SourceFiles/api/api_updates.cpp b/Telegram/SourceFiles/api/api_updates.cpp
index 1d41f6033c..bbb0ab721a 100644
--- a/Telegram/SourceFiles/api/api_updates.cpp
+++ b/Telegram/SourceFiles/api/api_updates.cpp
@@ -2692,17 +2692,6 @@ void Updates::feedUpdate(const MTPUpdate &update) {
_session->diceStickersPacks().apply(data);
} break;
- case mtpc_updatePeerHistoryNoForwards: {
- const auto &d = update.c_updatePeerHistoryNoForwards();
- const auto peerId = peerFromMTP(d.vpeer());
- if (const auto peer = session().data().peerLoaded(peerId)) {
- if (const auto user = peer->asUser()) {
- user->setNoForwardsFlags(
- d.is_my_enabled(),
- d.is_peer_enabled());
- }
- }
- } break;
}
}
diff --git a/Telegram/SourceFiles/boxes/boxes.style b/Telegram/SourceFiles/boxes/boxes.style
index d2a1e84a41..bcac6f7eaf 100644
--- a/Telegram/SourceFiles/boxes/boxes.style
+++ b/Telegram/SourceFiles/boxes/boxes.style
@@ -1200,3 +1200,9 @@ futureOwnerBox: Box(defaultBox) {
buttonHeight: 0px;
}
futureOwnerBoxSelect: collectibleBox;
+
+disableSharingIconPadding: margins(12px, 12px, 12px, 8px);
+disableSharingButtonLock: IconEmoji {
+ icon: icon {{ "emoji/premium_lock", activeButtonFg }};
+ padding: margins(-2px, 1px, 0px, 0px);
+}
diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
index f3c2c6fc43..4dd8c3e2c0 100644
--- a/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
+++ b/Telegram/SourceFiles/boxes/peers/edit_peer_info_box.cpp
@@ -2745,9 +2745,12 @@ void Controller::saveForwards() {
|| *_savingData.noForwards != _peer->allowsForwarding()) {
return continueSave();
}
+ using Flag = MTPmessages_ToggleNoForwards::Flag;
_api.request(MTPmessages_ToggleNoForwards(
+ MTP_flags(Flag()),
_peer->input(),
- MTP_bool(*_savingData.noForwards)
+ MTP_bool(*_savingData.noForwards),
+ MTPint()
)).done([=](const MTPUpdates &result) {
_peer->session().api().applyUpdates(result);
continueSave();
diff --git a/Telegram/SourceFiles/export/data/export_data_types.cpp b/Telegram/SourceFiles/export/data/export_data_types.cpp
index 66fdf9261a..cb6a0e391d 100644
--- a/Telegram/SourceFiles/export/data/export_data_types.cpp
+++ b/Telegram/SourceFiles/export/data/export_data_types.cpp
@@ -1858,6 +1858,15 @@ ServiceAction ParseServiceAction(
auto content = ActionChangeCreator();
content.newCreatorId = data.vnew_creator_id().v;
result.content = content;
+ }, [&](const MTPDmessageActionNoForwardsToggle &data) {
+ auto content = ActionNoForwardsToggle();
+ content.newValue = (data.vnew_value().type() == mtpc_boolTrue);
+ result.content = content;
+ }, [&](const MTPDmessageActionNoForwardsRequest &data) {
+ auto content = ActionNoForwardsRequest();
+ content.expired = data.is_expired();
+ content.newValue = (data.vnew_value().type() == mtpc_boolTrue);
+ result.content = content;
}, [](const MTPDmessageActionEmpty &data) {});
return result;
}
diff --git a/Telegram/SourceFiles/export/data/export_data_types.h b/Telegram/SourceFiles/export/data/export_data_types.h
index dc6cb4b8bf..20d08427cc 100644
--- a/Telegram/SourceFiles/export/data/export_data_types.h
+++ b/Telegram/SourceFiles/export/data/export_data_types.h
@@ -738,6 +738,15 @@ struct ActionSuggestBirthday {
Birthday birthday;
};
+struct ActionNoForwardsToggle {
+ bool newValue = false;
+};
+
+struct ActionNoForwardsRequest {
+ bool expired = false;
+ bool newValue = false;
+};
+
struct ActionNewCreatorPending {
UserId newCreatorId = 0;
};
@@ -800,6 +809,8 @@ struct ServiceAction {
ActionSuggestedPostSuccess,
ActionSuggestedPostRefund,
ActionSuggestBirthday,
+ ActionNoForwardsToggle,
+ ActionNoForwardsRequest,
ActionNewCreatorPending,
ActionChangeCreator> content;
};
diff --git a/Telegram/SourceFiles/export/output/export_output_html.cpp b/Telegram/SourceFiles/export/output/export_output_html.cpp
index 84d8e1d2d8..eca65598eb 100644
--- a/Telegram/SourceFiles/export/output/export_output_html.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_html.cpp
@@ -1553,6 +1553,14 @@ auto HtmlWriter::Wrap::pushMessage(
}() + (data.birthday.year()
? (' ' + QByteArray::number(data.birthday.year()))
: QByteArray());
+ }, [&](const ActionNoForwardsToggle &data) {
+ return serviceFrom
+ + (data.newValue
+ ? " disabled sharing in this chat"
+ : " enabled sharing in this chat");
+ }, [&](const ActionNoForwardsRequest &data) {
+ return serviceFrom
+ + " requested to enable sharing in this chat";
}, [&](const ActionNewCreatorPending &data) {
return peers.wrapUserName(data.newCreatorId)
+ " will become the new main admin in 7 days if "
diff --git a/Telegram/SourceFiles/export/output/export_output_json.cpp b/Telegram/SourceFiles/export/output/export_output_json.cpp
index 434c69ebc9..cddb7fd6d6 100644
--- a/Telegram/SourceFiles/export/output/export_output_json.cpp
+++ b/Telegram/SourceFiles/export/output/export_output_json.cpp
@@ -743,6 +743,15 @@ QByteArray SerializeMessage(
if (const auto year = data.birthday.year()) {
push("year", year);
}
+ }, [&](const ActionNoForwardsToggle &data) {
+ pushActor();
+ pushAction("no_forwards_toggle");
+ push("new_value", data.newValue);
+ }, [&](const ActionNoForwardsRequest &data) {
+ pushActor();
+ pushAction("no_forwards_request");
+ push("expired", data.expired);
+ push("new_value", data.newValue);
}, [&](const ActionNewCreatorPending &data) {
pushActor();
pushAction("new_creator_pending");
diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp
index ee803e75cf..7882698284 100644
--- a/Telegram/SourceFiles/history/history.cpp
+++ b/Telegram/SourceFiles/history/history.cpp
@@ -1382,6 +1382,13 @@ void History::applyServiceChanges(
peer->owner().notifyGiftAuctionGot({ data.vid().v, to });
}, [](const auto &) {});
}
+ }, [&](const MTPDmessageActionNoForwardsToggle &data) {
+ if (const auto user = peer->asUser()) {
+ const auto enabled = mtpIsTrue(data.vnew_value());
+ user->setNoForwardsFlags(
+ enabled && item->out(),
+ enabled && !item->out());
+ }
}, [](const auto &) {
});
}
diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp
index 15444a3550..1234c6909a 100644
--- a/Telegram/SourceFiles/history/history_item.cpp
+++ b/Telegram/SourceFiles/history/history_item.cpp
@@ -29,6 +29,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "storage/file_upload.h"
#include "storage/storage_shared_media.h"
#include "main/main_session.h"
+#include "main/main_app_config.h"
#include "main/main_session_settings.h"
#include "menu/menu_ttl_validator.h"
#include "apiwrap.h"
@@ -4946,6 +4947,29 @@ void HistoryItem::createServiceFromMtp(const MTPDmessageService &message) {
? SuggestRefundType::Expired
: SuggestRefundType::User;
finish->price = CreditsAmountFromTL(data.vprice());
+ } else if (type == mtpc_messageActionNoForwardsRequest) {
+ const auto &data = action.c_messageActionNoForwardsRequest();
+ const auto expired = data.is_expired();
+ const auto period = _history->session().appConfig()
+ .noForwardsRequestExpirePeriod();
+ const auto expiresAt = TimeId(_date + period);
+ const auto isExpired = expired
+ || (expiresAt <= base::unixtime::now());
+ auto mask = HistoryServiceNoForwardsRequest::Bit();
+ const auto actions = (!isExpired && !out())
+ ? SuggestionActions::NoForwardsRequest
+ : SuggestionActions::None;
+ if (actions != SuggestionActions::None) {
+ mask |= HistoryMessageReplyMarkup::Bit();
+ }
+ UpdateComponents(mask);
+ const auto request = Get();
+ request->expired = isExpired;
+ request->expiresAt = expiresAt;
+ if (actions != SuggestionActions::None) {
+ const auto markup = Get();
+ markup->updateSuggestControls(actions);
+ }
}
if (const auto replyTo = message.vreply_to()) {
replyTo->match([&](const MTPDmessageReplyHeader &data) {
@@ -6654,6 +6678,50 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
return result;
};
+ auto prepareNoForwardsToggle = [this](const MTPDmessageActionNoForwardsToggle &action) {
+ auto result = PreparedServiceText();
+ const auto enabled = mtpIsTrue(action.vnew_value());
+ const auto prevEnabled = mtpIsTrue(action.vprev_value());
+ if (enabled == prevEnabled) {
+ result.text = tr::lng_action_no_forwards_still_disabled(
+ tr::now,
+ tr::marked);
+ } else if (out()) {
+ result.text = (enabled
+ ? tr::lng_action_no_forwards_you_disabled
+ : tr::lng_action_no_forwards_you_enabled)(
+ tr::now,
+ tr::marked);
+ } else {
+ result.links.push_back(fromLink());
+ result.text = (enabled
+ ? tr::lng_action_no_forwards_disabled
+ : tr::lng_action_no_forwards_enabled)(
+ tr::now,
+ lt_from,
+ fromLinkText(),
+ tr::marked);
+ }
+ return result;
+ };
+
+ auto prepareNoForwardsRequest = [this](const MTPDmessageActionNoForwardsRequest &action) {
+ auto result = PreparedServiceText();
+ if (_from->isSelf()) {
+ result.text = tr::lng_action_no_forwards_request_you(
+ tr::now,
+ tr::marked);
+ } else {
+ result.links.push_back(fromLink());
+ result.text = tr::lng_action_no_forwards_request(
+ tr::now,
+ lt_from,
+ fromLinkText(),
+ tr::marked);
+ }
+ return result;
+ };
+
setServiceText(action.match(
prepareChatAddUserText,
prepareChatJoinedByLink,
@@ -6715,14 +6783,15 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) {
prepareStarGiftPurchaseOfferDeclined,
prepareNewCreatorPending,
prepareChangeCreator,
+ prepareNoForwardsToggle,
+ prepareNoForwardsRequest,
PrepareEmptyText,
PrepareErrorText));
- // Additional information.
- applyAction(action);
+ processAction(action);
}
-void HistoryItem::applyAction(const MTPMessageAction &action) {
+void HistoryItem::processAction(const MTPMessageAction &action) {
action.match([&](const MTPDmessageActionChatAddUser &data) {
if (const auto channel = _history->peer->asMegagroup()) {
const auto selfUserId = _history->session().userId();
diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h
index 4e21760ed3..8705b162c1 100644
--- a/Telegram/SourceFiles/history/history_item.h
+++ b/Telegram/SourceFiles/history/history_item.h
@@ -683,7 +683,7 @@ private:
void setReactions(const MTPMessageReactions *reactions);
[[nodiscard]] bool changeReactions(const MTPMessageReactions *reactions);
void setServiceMessageByAction(const MTPmessageAction &action);
- void applyAction(const MTPMessageAction &action);
+ void processAction(const MTPMessageAction &action);
void refreshMedia(const MTPMessageMedia *media);
void refreshSentMedia(const MTPMessageMedia *media);
void createServiceFromMtp(const MTPDmessage &message);
diff --git a/Telegram/SourceFiles/history/history_item_components.cpp b/Telegram/SourceFiles/history/history_item_components.cpp
index ced24a53f3..5655bff23a 100644
--- a/Telegram/SourceFiles/history/history_item_components.cpp
+++ b/Telegram/SourceFiles/history/history_item_components.cpp
@@ -1284,7 +1284,8 @@ bool HistoryMessageReplyMarkup::hiddenBy(Data::Media *media) const {
void HistoryMessageReplyMarkup::updateSuggestControls(
SuggestionActions actions) {
if (actions == SuggestionActions::AcceptAndDecline
- || actions == SuggestionActions::GiftOfferActions) {
+ || actions == SuggestionActions::GiftOfferActions
+ || actions == SuggestionActions::NoForwardsRequest) {
data.flags |= ReplyMarkupFlag::SuggestionAccept;
} else {
data.flags &= ~ReplyMarkupFlag::SuggestionAccept;
@@ -1320,6 +1321,19 @@ void HistoryMessageReplyMarkup::updateSuggestControls(
Visual(),
},
});
+ } else if (actions == SuggestionActions::NoForwardsRequest) {
+ data.rows.push_back({
+ {
+ Type::SuggestDecline,
+ tr::lng_action_no_forwards_reject(tr::now),
+ Visual(),
+ },
+ {
+ Type::SuggestAccept,
+ tr::lng_action_no_forwards_accept(tr::now),
+ Visual(),
+ },
+ });
} else if (actions == SuggestionActions::AcceptAndDecline) {
// ... rows ...
// [decline] | [accept]
diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h
index 50dc9b204e..213977e7e6 100644
--- a/Telegram/SourceFiles/history/history_item_components.h
+++ b/Telegram/SourceFiles/history/history_item_components.h
@@ -63,6 +63,7 @@ enum class SuggestionActions : uchar {
Decline,
AcceptAndDecline,
GiftOfferActions,
+ NoForwardsRequest,
};
struct HistoryMessageVia : RuntimeComponent {
@@ -738,6 +739,13 @@ struct HistoryServiceSuggestFinish
SuggestRefundType refundType = SuggestRefundType::None;
};
+struct HistoryServiceNoForwardsRequest
+: RuntimeComponent {
+ TimeId expiresAt = 0;
+ mtpRequestId requestId = 0;
+ bool expired = false;
+};
+
struct HistoryServiceGameScore
: RuntimeComponent
, HistoryServiceDependentData {
diff --git a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
index 4034082710..ec5f24344e 100644
--- a/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_context_menu.cpp
@@ -2048,25 +2048,30 @@ void AddSelectRestrictionAction(
if (addIcon && !menu->empty()) {
menu->addSeparator();
}
+ const auto user = peer->asUser();
auto button = base::make_unique_q(
menu->menu(),
menu->st().menu,
st::historyHasCustomEmoji,
- addIcon
+ ((addIcon && !user)
? st::historySponsoredAboutMenuLabelPosition
- : st::historyHasCustomEmojiPosition,
+ : st::historyHasCustomEmojiPosition),
(peer->isMegagroup()
- ? tr::lng_context_noforwards_info_group
+ ? tr::lng_context_noforwards_info_group(tr::now, tr::rich)
: (peer->isChannel())
- ? tr::lng_context_noforwards_info_channel
- : (peer->isUser() && peer->asUser()->isBot())
- ? tr::lng_context_noforwards_info_bot
- : peer->isUser()
- ? tr::lng_context_noforwards_info_user
- : tr::lng_context_noforwards_info_channel)(
- tr::now,
- tr::rich),
- addIcon ? &st::menuIconCopyright : nullptr);
+ ? tr::lng_context_noforwards_info_channel(tr::now, tr::rich)
+ : (user && user->isBot())
+ ? tr::lng_context_noforwards_info_bot(tr::now, tr::rich)
+ : user
+ ? ((user->flags() & UserDataFlag::NoForwardsMyEnabled)
+ ? tr::lng_context_noforwards_info_mine(tr::now, tr::rich)
+ : tr::lng_context_noforwards_info_his(
+ tr::now,
+ lt_user,
+ tr::bold(user->shortName()),
+ tr::rich))
+ : tr::lng_context_noforwards_info_channel(tr::now, tr::rich)),
+ (addIcon && !user) ? &st::menuIconCopyright : nullptr);
button->setAttribute(Qt::WA_TransparentForMouseEvents);
menu->addAction(std::move(button));
}
diff --git a/Telegram/SourceFiles/history/view/history_view_element.cpp b/Telegram/SourceFiles/history/view/history_view_element.cpp
index 605f4eacc3..1802c20e1e 100644
--- a/Telegram/SourceFiles/history/view/history_view_element.cpp
+++ b/Telegram/SourceFiles/history/view/history_view_element.cpp
@@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_sticker.h"
#include "history/view/media/history_view_large_emoji.h"
#include "history/view/media/history_view_custom_emoji.h"
+#include "history/view/media/history_view_no_forwards_request.h"
#include "history/view/media/history_view_suggest_decision.h"
#include "history/view/reactions/history_view_reactions_button.h"
#include "history/view/reactions/history_view_reactions.h"
@@ -1508,6 +1509,15 @@ void Element::refreshMedia(Element *replacing) {
this,
std::make_unique(this, emoji));
}
+ } else if (const auto nfr = item->Get()) {
+ _media = std::make_unique(
+ this,
+ GenerateNoForwardsRequestMedia(this, nfr),
+ MediaGenericDescriptor{
+ .maxWidth = st::chatSuggestInfoWidth,
+ .service = true,
+ .hideServiceText = true,
+ });
} else if (const auto decision = item->Get()) {
_media = std::make_unique(
this,
diff --git a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp
index 984651b68f..bc249c23e2 100644
--- a/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp
+++ b/Telegram/SourceFiles/history/view/media/history_view_media_generic.cpp
@@ -123,11 +123,17 @@ void MediaGeneric::draw(Painter &p, const PaintContext &context) const {
p.setPen(Qt::NoPen);
p.setBrush(context.st->msgServiceBg());
const auto rect = QRect(0, 0, width(), height());
- p.drawRoundedRect(rect, radius, radius);
- //if (context.selected()) {
- // p.setBrush(context.st->serviceTextPalette().selectBg);
- // p.drawRoundedRect(rect, radius, radius);
- //}
+ if (parent()->data()->inlineReplyKeyboard()) {
+ const auto half = rect.height() / 2;
+ p.setClipRect(rect - QMargins(0, 0, 0, half));
+ p.drawRoundedRect(rect, radius, radius);
+ p.setClipRect(rect - QMargins(0, rect.height() - half, 0, 0));
+ const auto small = Ui::BubbleRadiusSmall();
+ p.drawRoundedRect(rect, small, small);
+ p.setClipping(false);
+ } else {
+ p.drawRoundedRect(rect, radius, radius);
+ }
}
auto translated = 0;
diff --git a/Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.cpp b/Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.cpp
new file mode 100644
index 0000000000..5c3c5ea6a5
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.cpp
@@ -0,0 +1,137 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#include "history/view/media/history_view_no_forwards_request.h"
+
+#include "data/data_peer.h"
+#include "history/history_item.h"
+#include "history/history_item_components.h"
+#include "history/view/history_view_element.h"
+#include "history/view/media/history_view_media_generic.h"
+#include "lang/lang_keys.h"
+#include "ui/chat/chat_style.h"
+#include "ui/painter.h"
+#include "ui/text/text_utilities.h"
+#include "styles/style_chat.h"
+
+namespace HistoryView {
+namespace {
+
+class BulletPointPart final : public MediaGenericTextPart {
+public:
+ BulletPointPart(
+ TextWithEntities text,
+ QMargins margins);
+
+ void draw(
+ Painter &p,
+ not_null owner,
+ const PaintContext &context,
+ int outerWidth) const override;
+
+private:
+ int _bulletLeft = 0;
+ int _bulletTop = 0;
+
+};
+
+BulletPointPart::BulletPointPart(
+ TextWithEntities text,
+ QMargins margins)
+: MediaGenericTextPart(
+ std::move(text),
+ QMargins(
+ margins.left() + st::chatSuggestBulletLeftExtra + st::historyGroupAboutBulletSkip,
+ margins.top(),
+ margins.right(),
+ margins.bottom()),
+ st::serviceTextStyle,
+ {},
+ {},
+ style::al_left)
+, _bulletLeft(margins.left() + st::chatSuggestBulletLeftExtra)
+, _bulletTop(margins.top()) {
+}
+
+void BulletPointPart::draw(
+ Painter &p,
+ not_null owner,
+ const PaintContext &context,
+ int outerWidth) const {
+ MediaGenericTextPart::draw(p, owner, context, outerWidth);
+
+ const auto &font = st::serviceTextStyle.font;
+ const auto size = st::mediaUnreadSize;
+ const auto top = _bulletTop + (font->height - size) / 2;
+
+ p.setBrush(context.st->msgServiceFg());
+
+ PainterHighQualityEnabler hq(p);
+ p.setPen(Qt::NoPen);
+ p.drawEllipse(_bulletLeft, top, size, size);
+}
+
+} // namespace
+
+auto GenerateNoForwardsRequestMedia(
+ not_null parent,
+ not_null request)
+-> Fn,
+ Fn)>)> {
+ return [=](
+ not_null media,
+ Fn)> push) {
+ const auto item = parent->data();
+ const auto from = item->from();
+
+ auto pushText = [&](
+ TextWithEntities text,
+ QMargins margins,
+ style::align align = style::al_left) {
+ push(std::make_unique(
+ std::move(text),
+ margins,
+ st::serviceTextStyle,
+ base::flat_map(),
+ Ui::Text::MarkedContext(),
+ align));
+ };
+
+ pushText(
+ (from->isSelf()
+ ? tr::lng_action_no_forwards_request_you(
+ tr::now,
+ tr::marked)
+ : tr::lng_action_no_forwards_request(
+ tr::now,
+ lt_from,
+ tr::bold(from->shortName()),
+ tr::marked)),
+ st::chatSuggestInfoTitleMargin,
+ style::al_top);
+
+ const auto features = {
+ tr::lng_action_no_forwards_feature_forwarding(tr::now),
+ tr::lng_action_no_forwards_feature_saving(tr::now),
+ tr::lng_action_no_forwards_feature_copying(tr::now),
+ };
+ auto isLast = false;
+ auto index = 0;
+ const auto count = int(features.size());
+ for (const auto &feature : features) {
+ isLast = (++index == count);
+ push(std::make_unique(
+ TextWithEntities{ feature },
+ isLast
+ ? st::chatSuggestInfoLastMargin
+ : st::chatSuggestInfoMiddleMargin));
+ }
+ };
+}
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.h b/Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.h
new file mode 100644
index 0000000000..7ac6d49a64
--- /dev/null
+++ b/Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.h
@@ -0,0 +1,25 @@
+/*
+This file is part of Telegram Desktop,
+the official desktop application for the Telegram messaging service.
+
+For license and copyright information please follow this link:
+https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
+*/
+#pragma once
+
+struct HistoryServiceNoForwardsRequest;
+
+namespace HistoryView {
+
+class Element;
+class MediaGeneric;
+class MediaGenericPart;
+
+auto GenerateNoForwardsRequestMedia(
+ not_null parent,
+ not_null request
+) -> Fn,
+ Fn)>)>;
+
+} // namespace HistoryView
diff --git a/Telegram/SourceFiles/main/main_app_config.cpp b/Telegram/SourceFiles/main/main_app_config.cpp
index 5828b19437..088d013901 100644
--- a/Telegram/SourceFiles/main/main_app_config.cpp
+++ b/Telegram/SourceFiles/main/main_app_config.cpp
@@ -66,6 +66,12 @@ int AppConfig::stargiftConvertPeriodMax() const {
_account->mtp().isTestMode() ? 300 : (90 * 86400));
}
+int AppConfig::noForwardsRequestExpirePeriod() const {
+ return get(
+ u"no_forwards_request_expire_period"_q,
+ _account->mtp().isTestMode() ? 300 : 86400);
+}
+
const std::vector &AppConfig::startRefPrefixes() {
if (_startRefPrefixes.empty()) {
_startRefPrefixes = get>(
diff --git a/Telegram/SourceFiles/main/main_app_config.h b/Telegram/SourceFiles/main/main_app_config.h
index e1cc2f22be..365aa7940e 100644
--- a/Telegram/SourceFiles/main/main_app_config.h
+++ b/Telegram/SourceFiles/main/main_app_config.h
@@ -71,6 +71,7 @@ public:
[[nodiscard]] int quoteLengthMax() const;
[[nodiscard]] int stargiftConvertPeriodMax() const;
+ [[nodiscard]] int noForwardsRequestExpirePeriod() const;
[[nodiscard]] const std::vector &startRefPrefixes();
[[nodiscard]] bool starrefSetupAllowed() const;
diff --git a/Telegram/SourceFiles/main/main_session_settings.cpp b/Telegram/SourceFiles/main/main_session_settings.cpp
index 9169e20702..9e1b1cb7bc 100644
--- a/Telegram/SourceFiles/main/main_session_settings.cpp
+++ b/Telegram/SourceFiles/main/main_session_settings.cpp
@@ -68,6 +68,7 @@ QByteArray SessionSettings::serialize() const {
size += sizeof(qint32); // _setupEmailState
size += sizeof(qint32) // _moderateCommonGroups size
+ (_moderateCommonGroups.size() * sizeof(qint32));
+ size += sizeof(qint32);
auto result = QByteArray();
result.reserve(size);
@@ -153,6 +154,7 @@ QByteArray SessionSettings::serialize() const {
for (const auto &filterId : _moderateCommonGroups) {
stream << qint32(filterId);
}
+ stream << qint32(_disableSharingBoxShowsCount);
}
Ensures(result.size() == size);
@@ -226,6 +228,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
std::vector unreviewed;
qint32 setupEmailState = 0;
std::vector moderateCommonGroups;
+ qint32 disableSharingBoxShowsCount = 0;
stream >> versionTag;
if (versionTag == kVersionTag) {
@@ -659,6 +662,9 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
}
}
}
+ if (!stream.atEnd()) {
+ stream >> disableSharingBoxShowsCount;
+ }
if (stream.status() != QDataStream::Ok) {
LOG(("App Error: "
"Bad data for SessionSettings::addFromSerialized()"));
@@ -723,6 +729,7 @@ void SessionSettings::addFromSerialized(const QByteArray &serialized) {
}
_moderateCommonGroups = std::move(moderateCommonGroups);
+ _disableSharingBoxShowsCount = disableSharingBoxShowsCount;
if (version < 2) {
app.setLastSeenWarningSeen(appLastSeenWarningSeen == 1);
@@ -881,6 +888,20 @@ void SessionSettings::incrementPhotoEditorHintShown() {
}
}
+bool SessionSettings::shouldShowDisableSharingBox() const {
+ return _disableSharingBoxShowsCount < kDisableSharingBoxMaxShowsCount;
+}
+
+void SessionSettings::incrementDisableSharingBoxShown() {
+ if (shouldShowDisableSharingBox()) {
+ _disableSharingBoxShowsCount++;
+ }
+}
+
+void SessionSettings::resetDisableSharingBoxShown() {
+ _disableSharingBoxShowsCount = 0;
+}
+
std::vector SessionSettings::mutePeriods() const {
return _mutePeriods;
}
diff --git a/Telegram/SourceFiles/main/main_session_settings.h b/Telegram/SourceFiles/main/main_session_settings.h
index 56982c7902..34d13ccb2c 100644
--- a/Telegram/SourceFiles/main/main_session_settings.h
+++ b/Telegram/SourceFiles/main/main_session_settings.h
@@ -137,6 +137,10 @@ public:
[[nodiscard]] bool photoEditorHintShown() const;
void incrementPhotoEditorHintShown();
+ [[nodiscard]] bool shouldShowDisableSharingBox() const;
+ void incrementDisableSharingBoxShown();
+ void resetDisableSharingBoxShown();
+
[[nodiscard]] std::vector mutePeriods() const;
void addMutePeriod(TimeId period);
@@ -186,6 +190,7 @@ public:
private:
static constexpr auto kDefaultSupportChatsLimitSlice = 7 * 24 * 60 * 60;
static constexpr auto kPhotoEditorHintMaxShowsCount = 5;
+ static constexpr auto kDisableSharingBoxMaxShowsCount = 3;
struct ThreadId {
PeerId peerId;
@@ -211,6 +216,7 @@ private:
base::flat_map _ringtoneVolumes;
bool _dialogsFiltersEnabled = false;
int _photoEditorHintShowsCount = 0;
+ int _disableSharingBoxShowsCount = 0;
std::vector _mutePeriods;
TimeId _lastNonPremiumLimitDownload = 0;
TimeId _lastNonPremiumLimitUpload = 0;
diff --git a/Telegram/SourceFiles/mtproto/scheme/api.tl b/Telegram/SourceFiles/mtproto/scheme/api.tl
index 80863dcf62..d55e357516 100644
--- a/Telegram/SourceFiles/mtproto/scheme/api.tl
+++ b/Telegram/SourceFiles/mtproto/scheme/api.tl
@@ -33,7 +33,7 @@ inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile sti
inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia;
inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia;
inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia;
-inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true live_photo:flags.8?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia;
+inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia;
inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia;
inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia;
inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia;
@@ -126,7 +126,7 @@ messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_
messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia;
messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia;
messageMediaUnsupported#9f84f49e = MessageMedia;
-messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true live_photo:flags.11?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;
+messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia;
messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia;
messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia;
messageMediaGame#fdb19008 game:Game = MessageMedia;
@@ -203,6 +203,8 @@ messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declin
messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction;
messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction;
messageActionChangeCreator#e188503b new_creator_id:long = MessageAction;
+messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction;
+messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction;
dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog;
dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog;
@@ -457,7 +459,6 @@ updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Up
updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update;
updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update;
updateStarGiftCraftFail#ac072444 = Update;
-updatePeerHistoryNoForwards#5736b39a flags:# my_enabled:flags.0?true peer_enabled:flags.1?true peer:Peer = Update;
updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -2475,7 +2476,7 @@ messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:
messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions;
messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates;
messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates;
-messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates;
+messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates;
messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool;
messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates;
messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates;
diff --git a/Telegram/SourceFiles/ui/chat/chat.style b/Telegram/SourceFiles/ui/chat/chat.style
index b567b977c1..0963c42ea3 100644
--- a/Telegram/SourceFiles/ui/chat/chat.style
+++ b/Telegram/SourceFiles/ui/chat/chat.style
@@ -1100,6 +1100,7 @@ chatSuggestInfoWidth: 272px;
chatSuggestInfoTitleMargin: margins(16px, 16px, 16px, 6px);
chatSuggestInfoMiddleMargin: margins(16px, 4px, 16px, 4px);
chatSuggestInfoLastMargin: margins(16px, 4px, 16px, 16px);
+chatSuggestBulletLeftExtra: 16px;
chatSuggestTableMiddleMargin: margins(8px, 4px, 8px, 4px);
chatSuggestTableLastMargin: margins(8px, 4px, 8px, 16px);
chatSuggestInfoFullMargin: margins(16px, 16px, 16px, 16px);
diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style
index 6421139128..bb23ec9e19 100644
--- a/Telegram/SourceFiles/ui/menu_icons.style
+++ b/Telegram/SourceFiles/ui/menu_icons.style
@@ -204,6 +204,9 @@ menuIconCraftChance: icon{{ "menu/craft_chance-24x24", menuIconColor }};
menuIconCraft: icon{{ "menu/craft_start-24x24", menuIconColor }};
menuIconTagAdd: icon{{ "menu/tag_add-24x24", menuIconColor }};
menuIconTagEdit: icon{{ "menu/tag_edit-24x24", menuIconColor }};
+menuIconDownloadOff: icon {{ "menu/download_off-24x24", menuIconColor }};
+menuIconShareOff: icon {{ "menu/share_off-24x24", menuIconColor }};
+menuIconShareOn: icon {{ "menu/share_on-24x24", menuIconColor }};
menuIconTTLAny: icon {{ "menu/auto_delete_plain", menuIconColor }};
menuIconTTLAnyTextPosition: point(11px, 22px);
diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp
index 6c3dfdec1b..e6362d43e7 100644
--- a/Telegram/SourceFiles/window/window_peer_menu.cpp
+++ b/Telegram/SourceFiles/window/window_peer_menu.cpp
@@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_chat_participants.h"
#include "api/api_global_privacy.h"
#include "lang/lang_keys.h"
+#include "lottie/lottie_icon.h"
#include "ui/boxes/confirm_box.h"
#include "base/random.h"
#include "base/options.h"
@@ -57,6 +58,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/layers/generic_box.h"
#include "ui/delayed_activation.h"
#include "ui/vertical_list.h"
+#include "ui/controls/feature_list.h"
#include "ui/ui_utility.h"
#include "main/main_app_config.h"
#include "main/main_session.h"
@@ -79,6 +81,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_session_controller.h"
#include "window/window_controller.h"
#include "settings/sections/settings_advanced.h"
+#include "settings/sections/settings_premium.h"
+#include "settings/settings_common.h"
#include "support/support_helper.h"
#include "info/info_controller.h"
#include "info/info_memento.h"
@@ -105,6 +109,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_saved_sublist.h"
#include "data/data_histories.h"
#include "data/data_chat_filters.h"
+#include "data/data_peer_values.h"
#include "dialogs/dialogs_key.h"
#include "core/application.h"
#include "core/ui_integration.h"
@@ -118,6 +123,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_boxes.h"
#include "styles/style_window.h" // st::windowMinWidth
#include "styles/style_menu_icons.h"
+#include "styles/style_premium.h"
+#include "styles/style_settings.h"
#include
#include
@@ -304,6 +311,7 @@ private:
void addCreatePoll();
void addCreateTodoList();
void addThemeEdit();
+ void addToggleNoForwards();
void addBlockUser();
void addViewDiscussion();
void addDirectMessages();
@@ -1340,6 +1348,141 @@ void Filler::addThemeEdit() {
&st::menuIconChangeColors);
}
+void ShowDisableSharingBox(
+ not_null controller,
+ not_null peer,
+ Fn toggleNoForwards) {
+ controller->show(Box([=](not_null box) {
+ box->setStyle(st::showOrBox);
+ box->setWidth(st::boxWideWidth);
+ box->addTopButton(st::boxTitleClose, [=] {
+ box->closeBox();
+ });
+
+ const auto buttonPadding = QMargins(
+ st::showOrBox.buttonPadding.left(),
+ 0,
+ st::showOrBox.buttonPadding.right(),
+ 0);
+
+ auto icon = Settings::CreateLottieIcon(
+ box,
+ {
+ .name = u"stop"_q,
+ .sizeOverride = st::normalBoxLottieSize,
+ },
+ {});
+ box->verticalLayout()->add(
+ std::move(icon.widget),
+ st::disableSharingIconPadding,
+ style::al_top);
+
+ Ui::AddSkip(box->verticalLayout());
+
+ box->addRow(
+ object_ptr(
+ box,
+ tr::lng_disable_sharing_title(),
+ st::boostCenteredTitle),
+ QMargins(0, 0, 0, st::showOrTitleIconMargin) + buttonPadding,
+ style::al_top);
+
+ const auto features = std::vector{
+ {
+ st::menuIconShareOff,
+ tr::lng_disable_sharing_no_forwarding(tr::now),
+ { tr::lng_disable_sharing_no_forwarding_about(tr::now) },
+ },
+ {
+ st::menuIconDownloadOff,
+ tr::lng_disable_sharing_no_saving(tr::now),
+ { tr::lng_disable_sharing_no_saving_about(tr::now) },
+ },
+ };
+ for (const auto &feature : features) {
+ box->addRow(
+ Ui::MakeFeatureListEntry(box, feature),
+ st::boxRowPadding);
+ }
+
+ const auto button = box->addButton(rpl::single(QString()), [=] {
+ if (peer->session().premium()) {
+ toggleNoForwards(true);
+ box->closeBox();
+ } else {
+ Settings::ShowPremium(controller, u"no_forwards"_q);
+ }
+ });
+ button->setText(
+ Data::AmPremiumValue(&peer->session())
+ | rpl::map([](bool premium) {
+ if (premium) {
+ return TextWithEntities{
+ tr::lng_disable_sharing_button(tr::now) };
+ }
+ return Ui::Text::IconEmoji(
+ &st::disableSharingButtonLock
+ ).append(
+ ' ' + tr::lng_disable_sharing_unlock(tr::now));
+ }));
+
+ box->setShowFinishedCallback([animate = std::move(icon.animate)] {
+ animate(anim::repeat::once);
+ });
+ }));
+}
+
+void Filler::addToggleNoForwards() {
+ const auto user = _peer->asUser();
+ if (!user || user->isInaccessible() || user->isBot() || user->isSelf()) {
+ return;
+ }
+ const auto controller = _controller;
+ const auto peer = _peer;
+ const auto toggleNoForwards = [=](bool enabled) {
+ using Flag = MTPmessages_ToggleNoForwards::Flag;
+ peer->session().api().request(MTPmessages_ToggleNoForwards(
+ MTP_flags(Flag()),
+ peer->input(),
+ MTP_bool(enabled),
+ MTPint()
+ )).done([=](const MTPUpdates &result) {
+ peer->session().api().applyUpdates(result);
+ }).fail([=](const MTP::Error &error) {
+ if (error.type() != u"CHAT_NOT_MODIFIED"_q) {
+ controller->showToast(error.type());
+ }
+ }).send();
+ };
+ const auto disabledNow = !user->allowsForwarding();
+ _addAction(disabledNow
+ ? tr::lng_enable_sharing(tr::now)
+ : tr::lng_disable_sharing(tr::now), [=] {
+ if (controller->showFrozenError()) {
+ return;
+ } else if (disabledNow) {
+ toggleNoForwards(false);
+ return;
+ }
+ auto &settings = peer->session().settings();
+ if (!settings.shouldShowDisableSharingBox()) {
+#ifdef _DEBUG
+ settings.resetDisableSharingBoxShown();
+ peer->session().saveSettingsDelayed();
+#endif
+ if (peer->session().premium()) {
+ toggleNoForwards(true);
+ } else {
+ Settings::ShowPremium(controller, u"no_forwards"_q);
+ }
+ return;
+ }
+ settings.incrementDisableSharingBoxShown();
+ peer->session().saveSettingsDelayed();
+ ShowDisableSharingBox(controller, peer, toggleNoForwards);
+ }, disabledNow ? &st::menuIconShareOn : &st::menuIconShareOff);
+}
+
void Filler::addTTLSubmenu(bool addSeparator) {
if (_thread->asTopic() || !_peer || _peer->isMonoforum()) {
return; // #TODO later forum
@@ -1596,6 +1739,7 @@ void Filler::fillHistoryActions() {
addCreatePoll();
addCreateTodoList();
addThemeEdit();
+ addToggleNoForwards();
addViewDiscussion();
addDirectMessages();
addExportChat();
@@ -1625,6 +1769,7 @@ void Filler::fillProfileActions() {
addViewDiscussion();
addDirectMessages();
addExportChat();
+ addToggleNoForwards();
addToggleFolder();
addBlockUser();
addReport();