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 @@ + + + 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();