diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index cc060d2a60..6cf845c5fd 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -176,6 +176,8 @@ PRIVATE api/api_statistics_data_deserialize.h api/api_statistics_sender.cpp api/api_statistics_sender.h + api/api_suggest_post.cpp + api/api_suggest_post.h api/api_text_entities.cpp api/api_text_entities.h api/api_todo_lists.cpp diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index 1b2c0fc81f..cbfa6a937d 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -638,6 +638,7 @@ void SendConfirmedFile( edition.useSameMarkup = true; edition.useSameReplies = true; edition.useSameReactions = true; + edition.useSameSuggest = true; edition.savePreviousMedia = true; itemToEdit->applyEdition(std::move(edition)); } else { diff --git a/Telegram/SourceFiles/api/api_suggest_post.cpp b/Telegram/SourceFiles/api/api_suggest_post.cpp new file mode 100644 index 0000000000..6ed775bbee --- /dev/null +++ b/Telegram/SourceFiles/api/api_suggest_post.cpp @@ -0,0 +1,199 @@ +/* +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 "api/api_suggest_post.h" + +#include "apiwrap.h" +#include "base/unixtime.h" +#include "core/click_handler_types.h" +#include "data/data_session.h" +#include "history/history.h" +#include "history/history_item.h" +#include "history/history_item_components.h" +#include "lang/lang_keys.h" +#include "main/main_session.h" +#include "ui/boxes/choose_date_time.h" +#include "window/window_session_controller.h" + +namespace Api { +namespace { + +void SendApproval( + not_null controller, + not_null item, + TimeId scheduleDate = 0) { + using Flag = MTPmessages_ToggleSuggestedPostApproval::Flag; + const auto suggestion = item->Get(); + if (!suggestion + || suggestion->accepted + || suggestion->rejected + || suggestion->requestId) { + return; + } + + const auto id = item->fullId(); + const auto weak = base::make_weak(controller); + const auto session = &controller->session(); + const auto finish = [=] { + if (const auto item = session->data().message(id)) { + const auto suggestion = item->Get(); + if (suggestion) { + suggestion->requestId = 0; + } + } + }; + suggestion->requestId = session->api().request( + MTPmessages_ToggleSuggestedPostApproval( + MTP_flags(scheduleDate ? Flag::f_schedule_date : Flag()), + item->history()->peer->input, + MTP_int(item->id.bare), + MTP_int(scheduleDate), + MTPstring()) // reject_comment + ).done([=](const MTPUpdates &result) { + session->api().applyUpdates(result); + finish(); + }).fail([=](const MTP::Error &error) { + if (const auto window = weak.get()) { + window->showToast(error.type()); + } + finish(); + }).send(); +} + +void SendDecline( + not_null controller, + not_null item, + const QString &comment) { + using Flag = MTPmessages_ToggleSuggestedPostApproval::Flag; + const auto suggestion = item->Get(); + if (!suggestion + || suggestion->accepted + || suggestion->rejected + || suggestion->requestId) { + return; + } + + const auto id = item->fullId(); + const auto weak = base::make_weak(controller); + const auto session = &controller->session(); + const auto finish = [=] { + if (const auto item = session->data().message(id)) { + const auto suggestion = item->Get(); + if (suggestion) { + suggestion->requestId = 0; + } + } + }; + suggestion->requestId = session->api().request( + MTPmessages_ToggleSuggestedPostApproval( + MTP_flags(Flag::f_reject + | (comment.isEmpty() ? Flag() : Flag::f_reject_comment)), + item->history()->peer->input, + MTP_int(item->id.bare), + MTPint(), // schedule_date + MTP_string(comment)) + ).done([=](const MTPUpdates &result) { + session->api().applyUpdates(result); + finish(); + }).fail([=](const MTP::Error &error) { + if (const auto window = weak.get()) { + window->showToast(error.type()); + } + finish(); + }).send(); +} + +void RequestApprovalDate( + not_null controller, + not_null item) { + const auto weak = std::make_shared>(); + const auto done = [=](TimeId result) { + SendApproval(controller, item, result); + if (const auto strong = weak->data()) { + strong->closeBox(); + } + }; + auto dateBox = Box(Ui::ChooseDateTimeBox, Ui::ChooseDateTimeBoxArgs{ + .title = tr::lng_suggest_options_date(), + .submit = tr::lng_settings_save(), + .done = done, + .min = [] { return base::unixtime::now() + 1; }, + .time = (base::unixtime::now() + 86400), + }); + *weak = dateBox.data(); + controller->uiShow()->show(std::move(dateBox)); +} + +} // namespace + +std::shared_ptr AcceptClickHandler( + not_null item) { + const auto session = &item->history()->session(); + const auto id = item->fullId(); + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + const auto controller = my.sessionWindow.get(); + if (!controller || &controller->session() != session) { + return; + } + const auto item = session->data().message(id); + if (!item) { + return; + } + const auto suggestion = item->Get(); + if (!suggestion) { + return; + } else if (!suggestion->date) { + RequestApprovalDate(controller, item); + } else { + SendApproval(controller, item); + } + }); +} + +std::shared_ptr DeclineClickHandler( + not_null item) { + const auto session = &item->history()->session(); + const auto id = item->fullId(); + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + const auto controller = my.sessionWindow.get(); + if (!controller || &controller->session() != session) { + return; + } + const auto item = session->data().message(id); + if (!item) { + return; + } + const auto suggestion = item->Get(); + if (!suggestion) { + return; + } else { + SendDecline(controller, item, "sorry, bro.."); + } + }); +} + +std::shared_ptr SuggestChangesClickHandler( + not_null item) { + const auto session = &item->history()->session(); + const auto id = item->fullId(); + return std::make_shared([=](ClickContext context) { + const auto my = context.other.value(); + const auto window = my.sessionWindow.get(); + if (!window || &window->session() != session) { + return; + } + const auto item = session->data().message(id); + if (!item) { + return; + } + + }); +} + +} // namespace Api diff --git a/Telegram/SourceFiles/api/api_suggest_post.h b/Telegram/SourceFiles/api/api_suggest_post.h new file mode 100644 index 0000000000..0584ce7be7 --- /dev/null +++ b/Telegram/SourceFiles/api/api_suggest_post.h @@ -0,0 +1,21 @@ +/* +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 + +class ClickHandler; + +namespace Api { + +[[nodiscard]] std::shared_ptr AcceptClickHandler( + not_null item); +[[nodiscard]] std::shared_ptr DeclineClickHandler( + not_null item); +[[nodiscard]] std::shared_ptr SuggestChangesClickHandler( + not_null item); + +} // namespace Api diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index a1c6f380c9..7d74812110 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -2154,6 +2154,9 @@ void ApiWrap::saveDraftsToCloud() { if (!textWithTags.tags.isEmpty()) { flags |= MTPmessages_SaveDraft::Flag::f_entities; } + if (cloudDraft->suggest) { + flags |= MTPmessages_SaveDraft::Flag::f_suggested_post; + } auto entities = Api::EntitiesToMTP( _session, TextUtilities::ConvertTextTagsToEntities(textWithTags.tags), diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.cpp b/Telegram/SourceFiles/boxes/delete_messages_box.cpp index d880ab5860..cee747e797 100644 --- a/Telegram/SourceFiles/boxes/delete_messages_box.cpp +++ b/Telegram/SourceFiles/boxes/delete_messages_box.cpp @@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "lang/lang_keys.h" #include "main/main_session.h" #include "menu/menu_ttl_validator.h" +#include "ui/boxes/confirm_box.h" #include "ui/layers/generic_box.h" #include "ui/text/text_utilities.h" #include "ui/widgets/buttons.h" @@ -32,6 +33,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "styles/style_layers.h" #include "styles/style_boxes.h" +namespace { + +constexpr auto kPaidShowLive = 86400; + +} // namespace + DeleteMessagesBox::DeleteMessagesBox( QWidget*, not_null item, @@ -492,7 +499,41 @@ void DeleteMessagesBox::keyPressEvent(QKeyEvent *e) { } } +bool DeleteMessagesBox::hasPaidSuggestedPosts() const { + const auto now = base::unixtime::now(); + for (const auto &id : _ids) { + if (const auto item = _session->data().message(id)) { + if (item->isPaidSuggestedPost()) { + const auto date = item->date(); + if (now < date || now - date <= kPaidShowLive) { + return true; + } + } + } + } + return false; +} + void DeleteMessagesBox::deleteAndClear() { + if (hasPaidSuggestedPosts() && !_confirmedDeletePaidSuggestedPosts) { + const auto weak = Ui::MakeWeak(this); + const auto callback = [=](Fn close) { + close(); + if (const auto strong = weak.data()) { + strong->_confirmedDeletePaidSuggestedPosts = true; + strong->deleteAndClear(); + } + }; + AssertIsDebug(); + uiShow()->show(Ui::MakeConfirmBox({ + .text = u"You won't receive Stars for this post if you delete it now. The post must remain visible for at least 24 hours after it was published."_q, + .confirmed = callback, + .confirmText = u"Delete Anyway"_q, + .confirmStyle = &st::attentionBoxButton, + .title = u"Stars will be lost"_q, + })); + return; + } if (_revoke && _revokeRemember && _revokeRemember->toggled() diff --git a/Telegram/SourceFiles/boxes/delete_messages_box.h b/Telegram/SourceFiles/boxes/delete_messages_box.h index 9987fd8b32..ce5d430c8b 100644 --- a/Telegram/SourceFiles/boxes/delete_messages_box.h +++ b/Telegram/SourceFiles/boxes/delete_messages_box.h @@ -58,6 +58,7 @@ private: [[nodiscard]] bool hasScheduledMessages() const; [[nodiscard]] std::optional revokeText( not_null peer) const; + [[nodiscard]] bool hasPaidSuggestedPosts() const; const not_null _session; @@ -82,6 +83,7 @@ private: object_ptr _autoDeleteSettings = { nullptr }; int _fullHeight = 0; + bool _confirmedDeletePaidSuggestedPosts = false; Fn _deleteConfirmedCallback; diff --git a/Telegram/SourceFiles/data/data_drafts.cpp b/Telegram/SourceFiles/data/data_drafts.cpp index 95fc3c4f9c..5a61b486e8 100644 --- a/Telegram/SourceFiles/data/data_drafts.cpp +++ b/Telegram/SourceFiles/data/data_drafts.cpp @@ -56,6 +56,7 @@ Draft::Draft( mtpRequestId saveRequestId) : textWithTags(textWithTags) , reply(std::move(reply)) +, suggest(suggest) , cursor(cursor) , webpage(webpage) , saveRequestId(saveRequestId) { @@ -69,6 +70,7 @@ Draft::Draft( mtpRequestId saveRequestId) : textWithTags(field->getTextWithTags()) , reply(std::move(reply)) +, suggest(suggest) , cursor(field) , webpage(webpage) { } diff --git a/Telegram/SourceFiles/data/data_drafts.h b/Telegram/SourceFiles/data/data_drafts.h index 5af11ee198..683188eadb 100644 --- a/Telegram/SourceFiles/data/data_drafts.h +++ b/Telegram/SourceFiles/data/data_drafts.h @@ -257,6 +257,7 @@ using HistoryDrafts = base::flat_map>; } return (a->textWithTags == b->textWithTags) && (a->reply == b->reply) + && (a->suggest == b->suggest) && (a->webpage == b->webpage); } diff --git a/Telegram/SourceFiles/data/data_types.h b/Telegram/SourceFiles/data/data_types.h index c8f373a4f6..46da299a9b 100644 --- a/Telegram/SourceFiles/data/data_types.h +++ b/Telegram/SourceFiles/data/data_types.h @@ -353,6 +353,8 @@ enum class MessageFlag : uint64 { ReactionsAllowed = (1ULL << 50), HideDisplayDate = (1ULL << 51), + + PaidSuggestedPost = (1ULL << 52), }; inline constexpr bool is_flag_type(MessageFlag) { return true; } using MessageFlags = base::flags; diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index 9ce8ed0b79..bcef78a0e6 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -1593,6 +1593,10 @@ bool HistoryItem::isEditingMedia() const { return Has(); } +bool HistoryItem::isPaidSuggestedPost() const { + return _flags & MessageFlag::PaidSuggestedPost; +} + void HistoryItem::clearSavedMedia() { RemoveComponents(HistoryMessageSavedMediaData::Bit()); } @@ -1887,6 +1891,21 @@ void HistoryItem::applyEdition(HistoryMessageEdition &&edition) { } } + if (!edition.useSameSuggest) { + if (edition.suggest.exists) { + if (!Has()) { + AddComponents(HistoryMessageSuggestedPost::Bit()); + } + auto suggest = Get(); + suggest->stars = edition.suggest.stars; + suggest->date = edition.suggest.date; + suggest->accepted = edition.suggest.accepted; + suggest->rejected = edition.suggest.rejected; + } else { + RemoveComponents(HistoryMessageSuggestedPost::Bit()); + } + } + applyTTL(edition.ttl); setFactcheck(FromMTP(this, edition.mtpFactcheck)); @@ -2398,7 +2417,8 @@ bool HistoryItem::allowsSendNow() const { && isScheduled() && !isSending() && !hasFailed() - && !isEditingMedia(); + && !isEditingMedia() + && !isPaidSuggestedPost(); } bool HistoryItem::allowsReschedule() const { @@ -2425,7 +2445,8 @@ bool HistoryItem::allowsEdit(TimeId now) const { && !isTooOldForEdit(now) && (!_media || _media->allowsEdit()) && !isLegacyMessage() - && !isEditingMedia(); + && !isEditingMedia() + && !isPaidSuggestedPost(); } bool HistoryItem::allowsEditMedia() const { @@ -5928,8 +5949,15 @@ void HistoryItem::setServiceMessageByAction(const MTPmessageAction &action) { return prepareTodoAppendTasksText(); }; - auto prepareSuggestedPostApproval = [&](const MTPDmessageActionSuggestedPostApproval &) { - return PreparedServiceText{ { "process_suggested" } }; AssertIsDebug(); + auto prepareSuggestedPostApproval = [&](const MTPDmessageActionSuggestedPostApproval &data) { + if (data.is_balance_too_low()) { + return PreparedServiceText{ { u"balance too low :( need %1 stars"_q.arg(data.vstars_amount().value_or_empty()) } }; + } else if (data.is_rejected()) { + return PreparedServiceText{ { u"rejected :( comment: %1"_q.arg(qs(data.vreject_comment().value_or_empty())) } }; + } else if (const auto date = data.vschedule_date().value_or_empty()) { + return PreparedServiceText{ { u"approved!! for date: %1"_q.arg(langDateTime(base::unixtime::parse(date))) } }; + } + return PreparedServiceText{ { "approved!!" } }; AssertIsDebug(); }; auto prepareConferenceCall = [&](const MTPDmessageActionConferenceCall &) -> PreparedServiceText { diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 64e6880da6..71901f8e0c 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -312,6 +312,7 @@ public: [[nodiscard]] bool hasRealFromId() const; [[nodiscard]] bool isPostHidingAuthor() const; [[nodiscard]] bool isPostShowingAuthor() const; + [[nodiscard]] bool isPaidSuggestedPost() const; [[nodiscard]] bool isRegular() const; [[nodiscard]] bool isUploading() const; void sendFailed(); diff --git a/Telegram/SourceFiles/history/history_item_components.h b/Telegram/SourceFiles/history/history_item_components.h index 7e6c627d27..f701aecfb0 100644 --- a/Telegram/SourceFiles/history/history_item_components.h +++ b/Telegram/SourceFiles/history/history_item_components.h @@ -618,6 +618,7 @@ struct HistoryMessageSuggestedPost : RuntimeComponent { int stars = 0; TimeId date = 0; + mtpRequestId requestId = 0; bool accepted = false; bool rejected = false; }; diff --git a/Telegram/SourceFiles/history/history_item_edition.cpp b/Telegram/SourceFiles/history/history_item_edition.cpp index 1fb3482394..968a429c76 100644 --- a/Telegram/SourceFiles/history/history_item_edition.cpp +++ b/Telegram/SourceFiles/history/history_item_edition.cpp @@ -11,8 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "main/main_session.h" HistoryMessageEdition::HistoryMessageEdition( - not_null session, - const MTPDmessage &message) { + not_null session, + const MTPDmessage &message) +: suggest(HistoryMessageSuggestInfo(message.vsuggested_post())) { isEditHide = message.is_edit_hide(); isMediaUnread = message.is_media_unread(); editDate = message.vedit_date().value_or(-1); diff --git a/Telegram/SourceFiles/history/history_item_edition.h b/Telegram/SourceFiles/history/history_item_edition.h index c22ce713c8..8d0cd03aa2 100644 --- a/Telegram/SourceFiles/history/history_item_edition.h +++ b/Telegram/SourceFiles/history/history_item_edition.h @@ -30,11 +30,13 @@ struct HistoryMessageEdition { bool useSameReplies = false; bool useSameMarkup = false; bool useSameReactions = false; + bool useSameSuggest = false; bool savePreviousMedia = false; bool invertMedia = false; TextWithEntities textWithEntities; HistoryMessageMarkupData replyMarkup; HistoryMessageRepliesData replies; + HistoryMessageSuggestInfo suggest; const MTPMessageMedia *mtpMedia = nullptr; const MTPMessageReactions *mtpReactions = nullptr; const MTPFactCheck *mtpFactcheck = nullptr; diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 9b791852c9..3297854a55 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -762,6 +762,9 @@ MessageFlags FlagsFromMTP( | ((flags & MTP::f_invert_media) ? Flag::InvertMedia : Flag()) | ((flags & MTP::f_video_processing_pending) ? Flag::EstimatedDate + : Flag()) + | ((flags & MTP::f_paid_suggested_post) + ? Flag::PaidSuggestedPost : Flag()); } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 4b968b884a..29114bb086 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -3172,9 +3172,17 @@ void HistoryWidget::applySuggestOptions(SuggestPostOptions suggest) { controller(), _peer, suggest); - _suggestOptions->repaints() | rpl::start_with_next([=] { + _suggestOptions->updates() | rpl::start_with_next([=] { updateField(); + saveDraftWithTextNow(); }, _suggestOptions->lifetime()); + saveDraftWithTextNow(); +} + +void HistoryWidget::saveDraftWithTextNow() { + _saveDraftText = true; + _saveDraftStart = crl::now(); + saveDraft(); } void HistoryWidget::refreshSuggestPostToggle() { @@ -4644,9 +4652,7 @@ void HistoryWidget::send(Api::SendOptions options) { if (_preview) { _preview->apply({ .removed = true }); } - _saveDraftText = true; - _saveDraftStart = crl::now(); - saveDraft(); + saveDraftWithTextNow(); hideSelectorControlsAnimated(); @@ -7680,9 +7686,7 @@ void HistoryWidget::sendInlineResult(InlineBots::ResultSelected result) { result.messageSendingFrom.localId); clearFieldText(); - _saveDraftText = true; - _saveDraftStart = crl::now(); - saveDraft(); + saveDraftWithTextNow(); auto &bots = cRefRecentInlineBots(); const auto index = bots.indexOf(result.bot); @@ -8296,9 +8300,7 @@ bool HistoryWidget::sendExistingDocument( if (_autocomplete && _autocomplete->stickersShown()) { clearFieldText(); - //_saveDraftText = true; - //_saveDraftStart = crl::now(); - //saveDraft(); + //saveDraftWithTextNow(); // won't be needed if SendInlineBotResult will clear the cloud draft saveCloudDraft(); @@ -8634,10 +8636,7 @@ void HistoryWidget::setReplyFieldsFromProcessing() { refreshTopBarActiveChat(); } - _saveDraftText = true; - _saveDraftStart = crl::now(); - saveDraft(); - + saveDraftWithTextNow(); setInnerFocus(); } @@ -8702,10 +8701,7 @@ void HistoryWidget::editMessage( updateField(); SelectTextInFieldWithMargins(_field, selection); - _saveDraftText = true; - _saveDraftStart = crl::now(); - saveDraft(); - + saveDraftWithTextNow(); setInnerFocus(); } @@ -8794,9 +8790,7 @@ bool HistoryWidget::cancelReply(bool lastKeyboardUsed) { } } if (wasReply) { - _saveDraftText = true; - _saveDraftStart = crl::now(); - saveDraft(); + saveDraftWithTextNow(); } if (!_editMsgId && _keyboard->singleUse() @@ -8841,9 +8835,7 @@ void HistoryWidget::cancelEdit() { _saveEditMsgRequestId = 0; } - _saveDraftText = true; - _saveDraftStart = crl::now(); - saveDraft(); + saveDraftWithTextNow(); mouseMoveEvent(nullptr); if (!readyToForward() @@ -8891,6 +8883,7 @@ bool HistoryWidget::cancelSuggestPost() { _suggestOptions = nullptr; updateControlsVisibility(); updateControlsGeometry(); + saveDraftWithTextNow(); return true; } diff --git a/Telegram/SourceFiles/history/history_widget.h b/Telegram/SourceFiles/history/history_widget.h index f18577abe2..e225f5bf41 100644 --- a/Telegram/SourceFiles/history/history_widget.h +++ b/Telegram/SourceFiles/history/history_widget.h @@ -391,6 +391,7 @@ private: void saveDraft(bool delayed = false); void saveCloudDraft(); void saveDraftDelayed(); + void saveDraftWithTextNow(); void showMembersDropdown(); void windowIsVisibleChanged(); void saveFieldToHistoryLocalDraft(); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index fa9ed5edd2..8ced796f8f 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "history/view/history_view_message.h" +#include "api/api_suggest_post.h" #include "base/unixtime.h" #include "core/click_handler_types.h" // ClickHandlerContext #include "core/ui_integration.h" @@ -24,11 +25,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "boxes/share_box.h" #include "ui/effects/glare.h" #include "ui/effects/reaction_fly_animation.h" -#include "ui/rect.h" -#include "ui/round_rect.h" #include "ui/text/text_utilities.h" #include "ui/text/text_extended_data.h" #include "ui/power_saving.h" +#include "ui/rect.h" +#include "ui/round_rect.h" #include "data/components/factchecks.h" #include "data/components/sponsored_messages.h" #include "data/data_session.h" @@ -456,17 +457,45 @@ void Message::initPaidInformation() { const auto item = data(); if (!item->history()->peer->isUser()) { - if (const auto suggest = item->Get()) { + auto text = PreparedServiceText(); if (!suggest->stars && !suggest->date) { - setServicePreMessage({ { u"suggestion to publish for free anytime"_q } }); + text = { { u"suggestion to publish for free anytime"_q } }; } else if (!suggest->date) { - setServicePreMessage({ { u"suggestion to publish for %1 stars anytime"_q.arg(suggest->stars) }}); + text = { { u"suggestion to publish for %1 stars anytime"_q.arg(suggest->stars) } }; } else if (!suggest->stars) { - setServicePreMessage({ { u"suggestion to publish for free %1"_q.arg(langDateTime(base::unixtime::parse(suggest->date))) }}); + text = { { u"suggestion to publish for free %1"_q.arg(langDateTime(base::unixtime::parse(suggest->date))) } }; } else { - setServicePreMessage({ { u"suggestion to publish for %1 stars %2"_q.arg(suggest->stars).arg(langDateTime(base::unixtime::parse(suggest->date))) } }); + text = { { u"suggestion to publish for %1 stars %2"_q.arg(suggest->stars).arg(langDateTime(base::unixtime::parse(suggest->date))) } }; } + const auto channelIsAuthor = item->from()->isChannel(); + const auto amMonoforumAdmin = item->history()->peer->amMonoforumAdmin(); + const auto broadcast = item->history()->peer->monoforumBroadcast(); + const auto canDecline = item->isRegular() + && !(suggest->accepted || suggest->rejected) + && (channelIsAuthor ? !amMonoforumAdmin : amMonoforumAdmin); + const auto canAccept = canDecline + && (channelIsAuthor + ? !amMonoforumAdmin + : (amMonoforumAdmin + && broadcast + && broadcast->canPostMessages())); + if (canDecline) { + text.links.push_back(Api::DeclineClickHandler(item)); + text.text.append(", ").append(Ui::Text::Link("[Decline]", text.links.size())); + if (canAccept) { + text.links.push_back(Api::AcceptClickHandler(item)); + text.text.append(", ").append(Ui::Text::Link("[Accept]", text.links.size())); + + text.links.push_back(Api::SuggestChangesClickHandler(item)); + text.text.append(", ").append(Ui::Text::Link("[SuggestChanges]", text.links.size())); + } + } else if (suggest->accepted) { + text.text.append(", accepted!"); + } else if (suggest->rejected) { + text.text.append(", rejected :("); + } + setServicePreMessage(std::move(text)); } return; diff --git a/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp b/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp index da6566ce0f..8ba648a063 100644 --- a/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp +++ b/Telegram/SourceFiles/history/view/history_view_suggest_options.cpp @@ -94,15 +94,27 @@ void EditOptionsBox( st::settingsButtonNoIcon); time->setClickedCallback([=] { - box->uiShow()->show(Box(Ui::ChooseDateTimeBox, Ui::ChooseDateTimeBoxArgs{ + const auto weak = std::make_shared>(); + const auto parentWeak = Ui::MakeWeak(box); + const auto done = [=](TimeId result) { + if (parentWeak) { + state->date = result; + } + if (const auto strong = weak->data()) { + strong->closeBox(); + } + }; + auto dateBox = Box(Ui::ChooseDateTimeBox, Ui::ChooseDateTimeBoxArgs{ .title = tr::lng_suggest_options_date(), .submit = tr::lng_settings_save(), - .done = [=](TimeId result) { state->date = result; }, + .done = done, .min = [] { return base::unixtime::now() + 1; }, .time = (state->date.current() ? state->date.current() : (base::unixtime::now() + 86400)), - })); + }); + *weak = dateBox.data(); + box->uiShow()->show(std::move(dateBox)); }); Ui::AddSkip(container); @@ -172,7 +184,7 @@ void SuggestOptions::edit() { const auto apply = [=](SuggestPostOptions values) { _values = values; updateTexts(); - _repaints.fire({}); + _updates.fire({}); }; const auto broadcast = _peer->monoforumBroadcast(); const auto &appConfig = _peer->session().appConfig(); @@ -226,8 +238,8 @@ SuggestPostOptions SuggestOptions::values() const { return result; } -rpl::producer<> SuggestOptions::repaints() const { - return _repaints.events(); +rpl::producer<> SuggestOptions::updates() const { + return _updates.events(); } rpl::lifetime &SuggestOptions::lifetime() { diff --git a/Telegram/SourceFiles/history/view/history_view_suggest_options.h b/Telegram/SourceFiles/history/view/history_view_suggest_options.h index 26d11c1c70..8c5ef1ae41 100644 --- a/Telegram/SourceFiles/history/view/history_view_suggest_options.h +++ b/Telegram/SourceFiles/history/view/history_view_suggest_options.h @@ -28,7 +28,7 @@ public: [[nodiscard]] SuggestPostOptions values() const; - [[nodiscard]] rpl::producer<> repaints() const; + [[nodiscard]] rpl::producer<> updates() const; [[nodiscard]] rpl::lifetime &lifetime(); @@ -44,7 +44,7 @@ private: Ui::Text::String _text; SuggestPostOptions _values; - rpl::event_stream<> _repaints; + rpl::event_stream<> _updates; rpl::lifetime _lifetime;