From a9e35afbd75607165a87d6cd72dc3986fde735df Mon Sep 17 00:00:00 2001 From: John Preston Date: Tue, 17 Feb 2026 00:08:21 +0400 Subject: [PATCH] Implement disabling/enabling sharing. --- Telegram/CMakeLists.txt | 2 + Telegram/Resources/animations/stop.tgs | Bin 0 -> 24726 bytes .../Resources/icons/menu/download_off.svg | 7 + Telegram/Resources/icons/menu/share_off.svg | 9 ++ Telegram/Resources/icons/menu/share_on.svg | 7 + Telegram/Resources/langs/lang.strings | 28 +++- .../Resources/qrc/telegram/animations.qrc | 1 + Telegram/SourceFiles/api/api_suggest_post.cpp | 45 +++++- Telegram/SourceFiles/api/api_updates.cpp | 11 -- Telegram/SourceFiles/boxes/boxes.style | 6 + .../boxes/peers/edit_peer_info_box.cpp | 5 +- .../export/data/export_data_types.cpp | 9 ++ .../export/data/export_data_types.h | 11 ++ .../export/output/export_output_html.cpp | 8 + .../export/output/export_output_json.cpp | 9 ++ Telegram/SourceFiles/history/history.cpp | 7 + Telegram/SourceFiles/history/history_item.cpp | 75 ++++++++- Telegram/SourceFiles/history/history_item.h | 2 +- .../history/history_item_components.cpp | 16 +- .../history/history_item_components.h | 8 + .../view/history_view_context_menu.cpp | 29 ++-- .../history/view/history_view_element.cpp | 10 ++ .../view/media/history_view_media_generic.cpp | 16 +- .../history_view_no_forwards_request.cpp | 137 +++++++++++++++++ .../media/history_view_no_forwards_request.h | 25 +++ Telegram/SourceFiles/main/main_app_config.cpp | 6 + Telegram/SourceFiles/main/main_app_config.h | 1 + .../main/main_session_settings.cpp | 21 +++ .../SourceFiles/main/main_session_settings.h | 6 + Telegram/SourceFiles/mtproto/scheme/api.tl | 9 +- Telegram/SourceFiles/ui/chat/chat.style | 1 + Telegram/SourceFiles/ui/menu_icons.style | 3 + .../SourceFiles/window/window_peer_menu.cpp | 145 ++++++++++++++++++ 33 files changed, 635 insertions(+), 40 deletions(-) create mode 100644 Telegram/Resources/animations/stop.tgs create mode 100644 Telegram/Resources/icons/menu/download_off.svg create mode 100644 Telegram/Resources/icons/menu/share_off.svg create mode 100644 Telegram/Resources/icons/menu/share_on.svg create mode 100644 Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.cpp create mode 100644 Telegram/SourceFiles/history/view/media/history_view_no_forwards_request.h 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 0000000000000000000000000000000000000000..70ace96393b53c8b80dc3f0cac2a01b985fea6d0 GIT binary patch literal 24726 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 + + General / menu_download_off + + + + \ 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 @@ + + + General / menu_share_off + + + + + + \ 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 @@ + + + General / menu_share_on + + + + \ 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();