diff --git a/Telegram/SourceFiles/api/api_sending.cpp b/Telegram/SourceFiles/api/api_sending.cpp index fb096e6269..8655619c0a 100644 --- a/Telegram/SourceFiles/api/api_sending.cpp +++ b/Telegram/SourceFiles/api/api_sending.cpp @@ -165,25 +165,15 @@ void SendExistingMedia( flags |= MessageFlag::HasReplyInfo; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to; } - const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, action.options); InnerFillMessagePostFlags(action.options, peer, flags); if (silentPost) { sendFlags |= MTPmessages_SendMedia::Flag::f_silent; } const auto sendAs = action.options.sendAs; - const auto messageFromId = sendAs - ? sendAs->id - : anonymousPost - ? 0 - : session->userPeerId(); if (sendAs) { sendFlags |= MTPmessages_SendMedia::Flag::f_send_as; } - const auto messagePostAuthor = peer->isBroadcast() - ? session->user()->name() - : QString(); - auto caption = TextWithEntities{ message.textWithTags.text, TextUtilities::ConvertTextTagsToEntities(message.textWithTags.tags) @@ -219,11 +209,11 @@ void SendExistingMedia( history->addNewLocalMessage({ .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = action.replyTo, - .date = HistoryItem::NewMessageDate(action.options), + .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), .effectId = action.options.effectId, }, media, caption); @@ -361,25 +351,15 @@ bool SendDice(MessageToSend &message) { flags |= MessageFlag::HasReplyInfo; sendFlags |= MTPmessages_SendMedia::Flag::f_reply_to; } - const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, action.options); InnerFillMessagePostFlags(action.options, peer, flags); if (silentPost) { sendFlags |= MTPmessages_SendMedia::Flag::f_silent; } const auto sendAs = action.options.sendAs; - const auto messageFromId = sendAs - ? sendAs->id - : anonymousPost - ? 0 - : session->userPeerId(); if (sendAs) { sendFlags |= MTPmessages_SendMedia::Flag::f_send_as; } - const auto messagePostAuthor = peer->isBroadcast() - ? session->user()->name() - : QString(); - if (action.options.scheduled) { flags |= MessageFlag::IsOrWasScheduled; sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date; @@ -401,11 +381,11 @@ bool SendDice(MessageToSend &message) { history->addNewLocalMessage({ .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = action.replyTo, - .date = HistoryItem::NewMessageDate(action.options), + .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), .effectId = action.options.effectId, }, TextWithEntities(), MTP_messageMediaDice( MTP_int(0), @@ -529,7 +509,6 @@ void SendConfirmedFile( if (file->to.replyTo) { flags |= MessageFlag::HasReplyInfo; } - const auto anonymousPost = peer->amAnonymous(); FillMessagePostFlags(action, peer, flags); if (file->to.options.scheduled) { flags |= MessageFlag::IsOrWasScheduled; @@ -551,16 +530,6 @@ void SendConfirmedFile( if (file->to.options.invertCaption) { flags |= MessageFlag::InvertMedia; } - - const auto messageFromId = file->to.options.sendAs - ? file->to.options.sendAs->id - : anonymousPost - ? PeerId() - : session->userPeerId(); - const auto messagePostAuthor = peer->isBroadcast() - ? session->user()->name() - : QString(); - const auto media = MTPMessageMedia([&] { if (file->type == SendMediaType::Photo) { using Flag = MTPDmessageMediaPhoto::Flag; @@ -626,11 +595,11 @@ void SendConfirmedFile( history->addNewLocalMessage({ .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = file->to.replyTo, - .date = HistoryItem::NewMessageDate(file->to.options), + .date = NewMessageDate(file->to.options), .shortcutId = file->to.options.shortcutId, - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), .groupedId = groupId, .effectId = file->to.options.effectId, }, caption, media); diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index b757a88a61..b692c86515 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -3293,7 +3293,6 @@ void ApiWrap::forwardMessages( histories.readInbox(history); } const auto sendAs = action.options.sendAs; - const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, action.options); using SendFlag = MTPmessages_ForwardMessages::Flag; @@ -3385,23 +3384,14 @@ void ApiWrap::forwardMessages( const auto newId = FullMsgId( peer->id, _session->data().nextLocalMessageId()); - const auto self = _session->user(); - const auto messageFromId = sendAs - ? sendAs->id - : anonymousPost - ? PeerId(0) - : self->id; - const auto messagePostAuthor = peer->isBroadcast() - ? self->name() - : QString(); history->addNewLocalMessage({ .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = { .topicRootId = topMsgId }, - .date = HistoryItem::NewMessageDate(action.options), + .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), // forwarded messages don't have effects //.effectId = action.options.effectId, @@ -3476,8 +3466,6 @@ void ApiWrap::sendSharedContact( const auto newId = FullMsgId( peer->id, _session->data().nextLocalMessageId()); - const auto anonymousPost = peer->amAnonymous(); - auto flags = NewMessageFlags(peer); if (action.replyTo) { flags |= MessageFlag::HasReplyInfo; @@ -3489,22 +3477,14 @@ void ApiWrap::sendSharedContact( if (action.options.shortcutId) { flags |= MessageFlag::ShortcutMessage; } - const auto messageFromId = action.options.sendAs - ? action.options.sendAs->id - : anonymousPost - ? PeerId() - : _session->userPeerId(); - const auto messagePostAuthor = peer->isBroadcast() - ? _session->user()->name() - : QString(); const auto item = history->addNewLocalMessage({ .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = action.replyTo, - .date = HistoryItem::NewMessageDate(action.options), + .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), .effectId = action.options.effectId, }, TextWithEntities(), MTP_messageMediaContact( MTP_string(phone), @@ -3790,7 +3770,6 @@ void ApiWrap::sendMessage(MessageToSend &&message) { MTP_string(fields.url), MTP_int(page->pendingTill))); } - const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, action.options); FillMessagePostFlags(action, peer, flags); if ((exactWebPage && !ignoreWebPage && message.webPage.invert) @@ -3818,18 +3797,10 @@ void ApiWrap::sendMessage(MessageToSend &&message) { history->startSavingCloudDraft(draftTopicRootId); } const auto sendAs = action.options.sendAs; - const auto messageFromId = sendAs - ? sendAs->id - : anonymousPost - ? PeerId() - : _session->userPeerId(); if (sendAs) { sendFlags |= MTPmessages_SendMessage::Flag::f_send_as; mediaFlags |= MTPmessages_SendMedia::Flag::f_send_as; } - const auto messagePostAuthor = peer->isBroadcast() - ? _session->user()->name() - : QString(); if (action.options.scheduled) { flags |= MessageFlag::IsOrWasScheduled; sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date; @@ -3847,11 +3818,11 @@ void ApiWrap::sendMessage(MessageToSend &&message) { lastMessage = history->addNewLocalMessage({ .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = action.replyTo, - .date = HistoryItem::NewMessageDate(action.options), + .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), .effectId = action.options.effectId, }, sending, media); const auto done = [=]( @@ -3997,7 +3968,6 @@ void ApiWrap::sendInlineResult( flags |= MessageFlag::HasReplyInfo; sendFlags |= SendFlag::f_reply_to; } - const auto anonymousPost = peer->amAnonymous(); const auto silentPost = ShouldSendSilent(peer, action.options); FillMessagePostFlags(action, peer, flags); if (silentPost) { @@ -4016,30 +3986,22 @@ void ApiWrap::sendInlineResult( } const auto sendAs = action.options.sendAs; - const auto messageFromId = sendAs - ? sendAs->id - : anonymousPost ? PeerId() - : _session->userPeerId(); if (sendAs) { sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_send_as; } - const auto messagePostAuthor = peer->isBroadcast() - ? _session->user()->name() - : QString(); - _session->data().registerMessageRandomId(randomId, newId); data->addToHistory(history, { .id = newId.msg, .flags = flags, - .from = messageFromId, + .from = NewMessageFromId(action), .replyTo = action.replyTo, - .date = HistoryItem::NewMessageDate(action.options), + .date = NewMessageDate(action.options), .shortcutId = action.options.shortcutId, .viaBotId = ((bot && !action.options.hideViaBot) ? peerToUser(bot->id) : UserId()), - .postAuthor = messagePostAuthor, + .postAuthor = NewMessagePostAuthor(action), }); history->clearCloudDraft(topicRootId); diff --git a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp index 19ed13c31b..203a027f0b 100644 --- a/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp +++ b/Telegram/SourceFiles/boxes/peers/edit_peer_invite_link.cpp @@ -1577,9 +1577,11 @@ object_ptr EditLinkBox( const auto isGroup = !peer->isBroadcast(); const auto isPublic = peer->isChannel() && peer->asChannel()->isPublic(); auto object = Box([=](not_null box) { - const auto fill = [=] { - return Ui::FillCreateInviteLinkSubscriptionToggle(box, peer); - }; + const auto fill = isGroup + ? Fn(nullptr) + : [=] { + return Ui::FillCreateInviteLinkSubscriptionToggle(box, peer); + }; if (creating) { Ui::CreateInviteLinkBox(box, fill, isGroup, isPublic, done); } else { diff --git a/Telegram/SourceFiles/data/components/credits.cpp b/Telegram/SourceFiles/data/components/credits.cpp index 016d8ef4a4..34520f9230 100644 --- a/Telegram/SourceFiles/data/components/credits.cpp +++ b/Telegram/SourceFiles/data/components/credits.cpp @@ -9,6 +9,7 @@ For license and copyright information please follow this link: #include "api/api_credits.h" #include "data/data_user.h" +#include "main/main_app_config.h" #include "main/main_session.h" namespace Data { @@ -31,26 +32,10 @@ void Credits::apply(const MTPDupdateStarsBalance &data) { rpl::producer Credits::rateValue( not_null ownedBotOrChannel) { - // Should be replaced in the future. - if (_rate > 0) { - return rpl::single(_rate); - } - return [=](auto consumer) { - auto lifetime = rpl::lifetime(); - - const auto api = lifetime.make_state( - ownedBotOrChannel); - api->request( - ) | rpl::start_with_done([=] { - _rate = api->data().usdRate; - if (_rate > 0) { - consumer.put_next_copy(_rate); - consumer.put_done(); - } - }, lifetime); - - return lifetime; - }; + return rpl::single( + _session->appConfig().get( + u"stars_usd_withdraw_rate_x1000"_q, + 1200) / 1000.); } void Credits::load(bool force) { diff --git a/Telegram/SourceFiles/data/data_session.cpp b/Telegram/SourceFiles/data/data_session.cpp index 2a7a5dfd15..26b3b0718f 100644 --- a/Telegram/SourceFiles/data/data_session.cpp +++ b/Telegram/SourceFiles/data/data_session.cpp @@ -1295,24 +1295,31 @@ History *Session::historyLoaded(const PeerData *peer) { } void Session::deleteConversationLocally(not_null peer) { - const auto history = historyLoaded(peer); - if (history) { + const auto markLeft = [&] { + if (const auto channel = peer->asMegagroup()) { + channel->addFlags(ChannelDataFlag::Left); + if (const auto from = channel->getMigrateFromChat()) { + if (const auto migrated = historyLoaded(from)) { + migrated->updateChatListExistence(); + } + } + } + }; + if (const auto history = historyLoaded(peer)) { if (history->folderKnown()) { setChatPinned(history, FilterId(), false); } removeChatListEntry(history); history->clearFolder(); + + // We want to mark the channel as left before unloading the history, + // otherwise some parts of updating may return us to the chats list. + markLeft(); history->clear(peer->isChannel() ? History::ClearType::Unload : History::ClearType::DeleteChat); - } - if (const auto channel = peer->asMegagroup()) { - channel->addFlags(ChannelDataFlag::Left); - if (const auto from = channel->getMigrateFromChat()) { - if (const auto migrated = historyLoaded(from)) { - migrated->updateChatListExistence(); - } - } + } else { + markLeft(); } } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index e0f9256e9c..aef685564c 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -714,9 +714,7 @@ HistoryItem::HistoryItem( .flags = (MessageFlag::Local | MessageFlag::Sponsored | (history->peer->isChannel() ? MessageFlag::Post : MessageFlag(0))), - .date = HistoryItem::NewMessageDate(injectedAfter - ? injectedAfter->date() - : 0), + .date = NewMessageDate(injectedAfter ? injectedAfter->date() : 0), }) { const auto webpage = history->peer->owner().webpage( history->peer->owner().nextLocalMessageId().bare, @@ -804,15 +802,6 @@ TimeId HistoryItem::date() const { return _date; } -TimeId HistoryItem::NewMessageDate(TimeId scheduled) { - return scheduled ? scheduled : base::unixtime::now(); -} - -TimeId HistoryItem::NewMessageDate( - const Api::SendOptions &options) { - return options.shortcutId ? 1 : NewMessageDate(options.scheduled); -} - HistoryServiceDependentData *HistoryItem::GetServiceDependentData() { if (const auto pinned = Get()) { return pinned; @@ -2584,7 +2573,7 @@ bool HistoryItem::canReact() const { void HistoryItem::addPaidReaction(int count, bool anonymous) { Expects(count >= 0); - Expects(_history->peer->isBroadcast()); + Expects(_history->peer->isBroadcast() || isDiscussionPost()); if (!_reactions) { _reactions = std::make_unique(this); diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index a33a30a7bc..59833e834a 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -482,10 +482,6 @@ class HistoryItem final : public RuntimeComposer { [[nodiscard]] Data::MessagePosition position() const; [[nodiscard]] TimeId date() const; - [[nodiscard]] static TimeId NewMessageDate(TimeId scheduled); - [[nodiscard]] static TimeId NewMessageDate( - const Api::SendOptions &options); - [[nodiscard]] Data::Media *media() const { return _media.get(); } diff --git a/Telegram/SourceFiles/history/history_item_helpers.cpp b/Telegram/SourceFiles/history/history_item_helpers.cpp index 463f709524..dabd0ee838 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.cpp +++ b/Telegram/SourceFiles/history/history_item_helpers.cpp @@ -187,6 +187,32 @@ MessageFlags NewMessageFlags(not_null peer) { | (peer->isSelf() ? MessageFlag() : MessageFlag::Outgoing); } +TimeId NewMessageDate(TimeId scheduled) { + return scheduled ? scheduled : base::unixtime::now(); +} + +TimeId NewMessageDate(const Api::SendOptions &options) { + return options.shortcutId ? 1 : NewMessageDate(options.scheduled); +} + +PeerId NewMessageFromId(const Api::SendAction &action) { + return action.options.sendAs + ? action.options.sendAs->id + : action.history->peer->amAnonymous() + ? PeerId() + : action.history->session().userPeerId(); +} + +QString NewMessagePostAuthor(const Api::SendAction &action) { + return !action.history->peer->isBroadcast() + ? QString() + : (action.options.sendAs == action.history->peer) + ? QString() + : action.options.sendAs + ? action.options.sendAs->name() + : action.history->session().user()->name(); +} + bool ShouldSendSilent( not_null peer, const Api::SendOptions &options) { @@ -320,7 +346,7 @@ ClickHandlerPtr JumpToMessageClickHandler( const auto separate = Core::App().separateWindowFor(peer); const auto controller = separate ? separate->sessionController() - : peer->session().tryResolveWindow(); + : peer->session().tryResolveWindow(peer); if (controller) { auto params = Window::SectionShow{ Window::SectionShow::Way::Forward diff --git a/Telegram/SourceFiles/history/history_item_helpers.h b/Telegram/SourceFiles/history/history_item_helpers.h index 3d67e29ec1..dd5121dbed 100644 --- a/Telegram/SourceFiles/history/history_item_helpers.h +++ b/Telegram/SourceFiles/history/history_item_helpers.h @@ -83,6 +83,10 @@ void RequestDependentMessageStory( PeerId peerId, StoryId storyId); [[nodiscard]] MessageFlags NewMessageFlags(not_null peer); +[[nodiscard]] TimeId NewMessageDate(TimeId scheduled); +[[nodiscard]] TimeId NewMessageDate(const Api::SendOptions &options); +[[nodiscard]] PeerId NewMessageFromId(const Api::SendAction &action); +[[nodiscard]] QString NewMessagePostAuthor(const Api::SendAction &action); [[nodiscard]] bool ShouldSendSilent( not_null peer, const Api::SendOptions &options); diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index 2565a966ac..e704c422cf 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -37,6 +37,7 @@ For license and copyright information please follow this link: #include "api/api_who_reacted.h" #include "api/api_views.h" #include "layout/layout_selection.h" +#include "payments/payments_reaction_process.h" #include "window/section_widget.h" #include "window/window_adaptive.h" #include "window/window_session_controller.h" @@ -2802,6 +2803,13 @@ void ListWidget::reactionChosen(ChosenReaction reaction) { const auto item = session().data().message(reaction.context); if (!item) { return; + } else if (reaction.id.paid()) { + Payments::ShowPaidReactionDetails( + controller(), + item, + viewForItem(item), + HistoryReactionSource::Selector); + return; } else if (_delegate->listShowReactPremiumError(item, reaction.id)) { if (_menu) { _menu->hideMenu(); diff --git a/Telegram/SourceFiles/history/view/history_view_message.cpp b/Telegram/SourceFiles/history/view/history_view_message.cpp index 83a7534509..71baf550f5 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.cpp +++ b/Telegram/SourceFiles/history/view/history_view_message.cpp @@ -842,7 +842,7 @@ QSize Message::performCountOptimalSize() { refreshReactions(); } refreshRightBadge(); - refreshInfoSkipBlock(); + refreshInfoSkipBlock(textItem); const auto botTop = item->isFakeAboutView() ? Get() @@ -4293,13 +4293,28 @@ int Message::resizeContentGetHeight(int newWidth) { return height(); } + const auto item = data(); + const auto postShowingAuthor = item->isPostShowingAuthor() ? 1 : 0; + if (_postShowingAuthor != postShowingAuthor) { + _postShowingAuthor = postShowingAuthor; + _fromNameVersion = -1; + previousInBlocksChanged(); + + const auto size = _bottomInfo.currentSize(); + _bottomInfo.update(BottomInfoDataFromMessage(this), newWidth); + if (size != _bottomInfo.currentSize()) { + // maxWidth may have changed, full recount required. + setPendingResize(); + return resizeGetHeight(newWidth); + } + } + auto newHeight = minHeight(); if (const auto service = Get()) { service->resizeToWidth(newWidth, delegate()->elementIsChatWide()); } - const auto item = data(); const auto botTop = item->isFakeAboutView() ? Get() : nullptr; @@ -4307,14 +4322,6 @@ int Message::resizeContentGetHeight(int newWidth) { const auto mediaDisplayed = media ? media->isDisplayed() : false; const auto bubble = drawBubble(); - const auto postShowingAuthor = item->isPostShowingAuthor() ? 1 : 0; - if (_postShowingAuthor != postShowingAuthor) { - _postShowingAuthor = postShowingAuthor; - _bottomInfo.update(BottomInfoDataFromMessage(this), newWidth); - _fromNameVersion = -1; - previousInBlocksChanged(); - } - item->resolveDependent(); // This code duplicates countGeometry() but also resizes media. @@ -4539,17 +4546,16 @@ QSize Message::performCountCurrentSize(int newWidth) { return { newWidth, newHeight }; } -void Message::refreshInfoSkipBlock() { - const auto item = data(); +void Message::refreshInfoSkipBlock(HistoryItem *textItem) { const auto media = this->media(); const auto hasTextSkipBlock = [&] { - if (item->_text.empty()) { + if (!textItem || textItem->_text.empty()) { if (const auto media = data()->media()) { return media->storyExpired(); } return false; - } else if (item->Has() - || factcheckBlock()) { + } else if (factcheckBlock() + || data()->Has()) { return false; } else if (media && media->isDisplayed() && !_invertMedia) { return false; diff --git a/Telegram/SourceFiles/history/view/history_view_message.h b/Telegram/SourceFiles/history/view/history_view_message.h index dd223a4d59..6d7cdf9a35 100644 --- a/Telegram/SourceFiles/history/view/history_view_message.h +++ b/Telegram/SourceFiles/history/view/history_view_message.h @@ -287,7 +287,7 @@ class Message final : public Element { void ensureRightAction() const; void refreshTopicButton(); - void refreshInfoSkipBlock(); + void refreshInfoSkipBlock(HistoryItem *textItem); [[nodiscard]] int monospaceMaxWidth() const; void validateInlineKeyboard(HistoryMessageReplyMarkup *markup); diff --git a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp index 01aefa3c58..b65802d4c8 100644 --- a/Telegram/SourceFiles/history/view/media/history_view_photo.cpp +++ b/Telegram/SourceFiles/history/view/media/history_view_photo.cpp @@ -258,6 +258,7 @@ QSize Photo::countCurrentSize(int newWidth) { const auto enlargeOuter = 2 * st::historyPageEnlargeSkip + enlargeInner; const auto showEnlarge = (_parent->media() != this) && _parent->data()->media() + && !_parent->data()->isSponsored() && _parent->data()->media()->webpage() && _parent->data()->media()->webpage()->suggestEnlargePhoto() && (newWidth >= enlargeOuter) diff --git a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp index fb99cc6356..c1be784a2b 100644 --- a/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp +++ b/Telegram/SourceFiles/history/view/reactions/history_view_reactions.cpp @@ -141,14 +141,14 @@ void InlineList::layoutButtons() { not_null b) { const auto acount = a->count - (a->my ? 1 : 0); const auto bcount = b->count - (b->my ? 1 : 0); - if (acount > bcount) { - return true; - } else if (acount < bcount) { - return false; - } else if (b->id.paid()) { + if (b->id.paid()) { return false; } else if (a->id.paid()) { return true; + } else if (acount > bcount) { + return true; + } else if (acount < bcount) { + return false; } return ranges::find(list, a->id, &::Data::Reaction::id) < ranges::find(list, b->id, &::Data::Reaction::id); diff --git a/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp b/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp index 756fb72296..a482628733 100644 --- a/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp +++ b/Telegram/SourceFiles/info/channel_statistics/earn/info_channel_earn_list.cpp @@ -386,7 +386,13 @@ void InnerWidget::load() { void InnerWidget::fill() { const auto container = this; - const auto &data = _state.currencyEarn; + const auto channel = _peer->asChannel(); + const auto canViewCurrencyEarn = channel + ? (channel->flags() & ChannelDataFlag::CanViewRevenue) + : true; + const auto &data = canViewCurrencyEarn + ? _state.currencyEarn + : Data::EarnStatistics(); const auto &creditsData = _state.creditsEarn; auto currencyStateValue = rpl::single( @@ -417,7 +423,6 @@ void InnerWidget::fill() { const auto nonInteractive = base::unixtime::now() < kNonInteractivePeriod; const auto session = &_peer->session(); - const auto channel = _peer->asChannel(); const auto withdrawalEnabled = WithdrawalEnabled(session) && !nonInteractive; const auto makeContext = [=](not_null l) { @@ -1486,10 +1491,15 @@ void InnerWidget::fill() { [] {}); } if (!isLocked) { - Api::RestrictSponsored(channel, value, [=](const QString &e) { - toggled->fire(false); - _controller->uiShow()->showToast(e); - }); + const auto weak = Ui::MakeWeak(this); + const auto show = _controller->uiShow(); + const auto failed = [=](const QString &e) { + if (weak.data()) { + toggled->fire(false); + show->showToast(e); + } + }; + Api::RestrictSponsored(channel, value, failed); } }, button->lifetime()); diff --git a/Telegram/SourceFiles/main/session/send_as_peers.cpp b/Telegram/SourceFiles/main/session/send_as_peers.cpp index ab75de1031..050c87f6ed 100644 --- a/Telegram/SourceFiles/main/session/send_as_peers.cpp +++ b/Telegram/SourceFiles/main/session/send_as_peers.cpp @@ -29,14 +29,16 @@ SendAsPeers::SendAsPeers(not_null session) ) | rpl::map([=](const Data::PeerUpdate &update) { const auto peer = update.peer; const auto channel = peer->asChannel(); - return std::tuple( - peer, - peer->amAnonymous(), - channel ? channel->isPublic() : false); + const auto bits = 0 + | (peer->amAnonymous() ? (1 << 0) : 0) + | ((channel && channel->isPublic()) ? (1 << 1) : 0) + | ((channel && channel->addsSignature()) ? (1 << 2) : 0) + | ((channel && channel->signatureProfiles()) ? (1 << 3) : 0); + return std::tuple(peer, bits); }) | rpl::distinct_until_changed( - ) | rpl::filter([=](not_null peer, bool, bool) { - return _lists.contains(peer); - }) | rpl::start_with_next([=](not_null peer, bool, bool) { + ) | rpl::filter([=](not_null peer, int) { + return _lists.contains(peer) || _lastRequestTime.contains(peer); + }) | rpl::start_with_next([=](not_null peer, int) { refresh(peer, true); }, _lifetime); } @@ -115,6 +117,12 @@ not_null SendAsPeers::ResolveChosen( not_null peer, const std::vector &list, PeerId chosen) { + const auto fallback = peer->amAnonymous() + ? peer + : peer->session().user(); + if (!chosen) { + chosen = fallback->id; + } const auto i = ranges::find(list, chosen, [](const SendAsPeer &as) { return as.peer->id; }); @@ -122,9 +130,7 @@ not_null SendAsPeers::ResolveChosen( ? i->peer : !list.empty() ? list.front().peer - : peer->amAnonymous() - ? peer - : peer->session().user(); + : fallback; } void SendAsPeers::request(not_null peer) { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 15fa0b8f17..a49961f3e9 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1186,23 +1186,32 @@ Image *MainWidget::newBackgroundThumb() { } void MainWidget::setInnerFocus() { + const auto setTo = [&](auto &&widget) { + if (widget->isHidden()) { + // If we try setting focus inside a hidden widget, we may + // end up focusing search field in dialogs on window activation. + setFocus(); + } else { + widget->setInnerFocus(); + } + }; if (_dialogs && _dialogs->searchHasFocus()) { - _dialogs->setInnerFocus(); + setTo(_dialogs); } else if (_hider || !_history->peer()) { if (!_hider && _mainSection) { - _mainSection->setInnerFocus(); + setTo(_mainSection); } else if (!_hider && _thirdSection) { - _thirdSection->setInnerFocus(); + setTo(_thirdSection); } else if (_dialogs) { - _dialogs->setInnerFocus(); + setTo(_dialogs); } else { // Maybe we're just closing a child window, content is destroyed. _history->setFocus(); } } else if (_mainSection) { - _mainSection->setInnerFocus(); + setTo(_mainSection); } else { - _history->setInnerFocus(); + setTo(_history); } } @@ -1287,6 +1296,9 @@ void MainWidget::showHistory( const SectionShow ¶ms, MsgId showAtMsgId) { if (peerId && _controller->window().locked()) { + if (params.activation != anim::activation::background) { + _controller->window().activate(); + } return; } else if (auto peer = session().data().peerLoaded(peerId)) { if (peer->migrateTo()) { @@ -1309,6 +1321,9 @@ void MainWidget::showHistory( && _mainSection && _mainSection->showMessage(peerId, params, showAtMsgId)) { session().data().hideShownSpoilers(); + if (params.activation != anim::activation::background) { + _controller->window().activate(); + } return; } else if (showHistoryInDifferentWindow(peerId, params, showAtMsgId)) { return; @@ -1494,16 +1509,26 @@ void MainWidget::showMessage( if (!v::is_null(params.origin)) { if (_mainSection) { if (_mainSection->showMessage(peerId, params, itemId)) { + if (params.activation != anim::activation::background) { + _controller->window().activate(); + } return; } } else if (_history->peer() == item->history()->peer) { + // showHistory may be redirected to different window, + // so we don't call activate() on current controller's window. showHistory(peerId, params, itemId); return; } } if (const auto topic = item->topic()) { _controller->showTopic(topic, item->id, params); + if (params.activation != anim::activation::background) { + _controller->window().activate(); + } } else { + // showPeerHistory may be redirected to different window, + // so we don't call activate() on current controller's window. _controller->showPeerHistory( item->history(), params, diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 96c5c93c8c..3cca163318 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -1515,10 +1515,10 @@ void OverlayWidget::refreshSponsoredButtonGeometry() { (controllerBottom // Duplicated in recountSkipTop(). - ((_streamed && _streamed->controls) ? (_streamed->controls->height() - + st::mediaviewCaptionMargin.height()) + + st::mediaviewCaptionPadding.bottom()) : 0) - _sponsoredButton->height() - - st::mediaviewCaptionPadding.bottom())); + - st::mediaviewCaptionMargin.height())); Ui::SendPendingMoveResizeEvents(_sponsoredButton.get()); } @@ -3488,6 +3488,8 @@ void OverlayWidget::displayPhoto( initStreaming(); } + initSponsoredButton(); + refreshCaption(); _blurred = true; @@ -5963,7 +5965,7 @@ void OverlayWidget::handleMouseRelease( QVariant::fromValue(ClickHandlerContext{ .itemId = _message ? _message->fullId() : FullMsgId(), .sessionWindow = base::make_weak(findWindow()), - .show = _stories ? _stories->uiShow() : nullptr, + .show = _stories ? _stories->uiShow() : uiShow(), .dark = true, }) }); diff --git a/Telegram/SourceFiles/payments/payments_reaction_process.cpp b/Telegram/SourceFiles/payments/payments_reaction_process.cpp index 57de72432a..d66063b330 100644 --- a/Telegram/SourceFiles/payments/payments_reaction_process.cpp +++ b/Telegram/SourceFiles/payments/payments_reaction_process.cpp @@ -11,6 +11,7 @@ For license and copyright information please follow this link: #include "boxes/send_credits_box.h" // CreditsEmojiSmall. #include "core/ui_integration.h" // MarkedTextContext. #include "data/components/credits.h" +#include "data/data_channel.h" #include "data/data_message_reactions.h" #include "data/data_session.h" #include "data/data_user.h" @@ -120,7 +121,8 @@ void ShowPaidReactionDetails( not_null item, HistoryView::Element *view, HistoryReactionSource source) { - Expects(item->history()->peer->isBroadcast()); + Expects(item->history()->peer->isBroadcast() + || item->isDiscussionPost()); const auto show = controller->uiShow(); const auto itemId = item->fullId(); @@ -229,11 +231,13 @@ void ShowPaidReactionDetails( } ranges::sort(top, ranges::greater(), &Ui::PaidReactionTop::count); + const auto linked = item->discussionPostOriginalSender(); + const auto channel = (linked ? linked : item->history()->peer.get()); state->selectBox = show->show(Ui::MakePaidReactionBox({ .chosen = chosen, .max = max, .top = std::move(top), - .channel = item->history()->peer->name(), + .channel = channel->name(), .submit = std::move(submitText), .balanceValue = session->credits().balanceValue(), .send = [=](int count, bool anonymous) { diff --git a/Telegram/SourceFiles/ui/boxes/edit_invite_link_session.cpp b/Telegram/SourceFiles/ui/boxes/edit_invite_link_session.cpp index 8b0260d3a9..7bd6ee08fc 100644 --- a/Telegram/SourceFiles/ui/boxes/edit_invite_link_session.cpp +++ b/Telegram/SourceFiles/ui/boxes/edit_invite_link_session.cpp @@ -7,7 +7,7 @@ For license and copyright information please follow this link: */ #include "ui/boxes/edit_invite_link_session.h" -#include "api/api_credits.h" +#include "data/components/credits.h" #include "data/data_peer.h" #include "data/data_session.h" #include "data/stickers/data_custom_emoji.h" @@ -39,7 +39,7 @@ InviteLinkSubscriptionToggle FillCreateInviteLinkSubscriptionToggle( not_null box, not_null peer) { struct State final { - float64 usdRate = 0; + rpl::variable usdRate = 0; }; const auto state = box->lifetime().make_state(); const auto currency = u"USD"_q; @@ -73,7 +73,7 @@ InviteLinkSubscriptionToggle FillCreateInviteLinkSubscriptionToggle( st, tr::lng_group_invite_subscription_ph(), QString(), - maxCredits); + std::pow(QString::number(maxCredits).size(), 10)); wrap->toggledValue() | rpl::start_with_next([=](bool shown) { if (shown) { input->setFocus(); @@ -97,11 +97,15 @@ InviteLinkSubscriptionToggle FillCreateInviteLinkSubscriptionToggle( }, input->lifetime()); ToggleChildrenVisibility(inputContainer, true); QObject::connect(input, &Ui::MaskedInputField::changed, [=] { + const auto amount = input->getLastText().toDouble(); + if (amount > maxCredits) { + input->setText(QString::number(maxCredits)); + } priceOverlay->update(); }); priceOverlay->paintRequest( ) | rpl::start_with_next([=, right = st::boxRowPadding.right()] { - if (state->usdRate <= 0) { + if (state->usdRate.current() <= 0) { return; } const auto amount = input->getLastText().toDouble(); @@ -111,7 +115,9 @@ InviteLinkSubscriptionToggle FillCreateInviteLinkSubscriptionToggle( const auto text = tr::lng_group_invite_subscription_price( tr::now, lt_cost, - Ui::FillAmountAndCurrency(amount * state->usdRate, currency)); + Ui::FillAmountAndCurrency( + amount * state->usdRate.current(), + currency)); auto p = QPainter(priceOverlay); p.setFont(st.placeholderFont); p.setPen(st.placeholderFg); @@ -120,16 +126,7 @@ InviteLinkSubscriptionToggle FillCreateInviteLinkSubscriptionToggle( p.drawText(priceOverlay->rect() - m, text, style::al_right); }, priceOverlay->lifetime()); - { - auto &lifetime = priceOverlay->lifetime(); - const auto api = lifetime.make_state( - peer); - api->request( - ) | rpl::start_with_done([=] { - state->usdRate = api->data().usdRate; - priceOverlay->update(); - }, priceOverlay->lifetime()); - } + state->usdRate = peer->session().credits().rateValue(peer); const auto arrow = Ui::Text::SingleCustomEmoji( peer->owner().customEmojiManager().registerInternalEmoji( diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index 8fcee8adb1..8cfdb0a8b9 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -2518,12 +2518,12 @@ void SessionController::showMessage( std::make_shared( item->history()), params); + if (params.activation != anim::activation::background) { + controller->window().activate(); + } } else { controller->content()->showMessage(item, params); } - if (params.activation != anim::activation::background) { - controller->window().activate(); - } }); } diff --git a/changelog.txt b/changelog.txt index e5c349e748..80729610f0 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,10 @@ +5.4.1 (17.08.24) + +- Fix crash when sending Star Reaction in comments. +- Fix loading "Send As" channels in a channel. +- Place Star Reaction always first in list. +- Removed paid Invite Links in groups. + 5.4 (14.08.24) - Super Channels with post authors' profiles. diff --git a/docs/building-win-x64.md b/docs/building-win-x64.md index 2e6a15b3ca..de895727aa 100644 --- a/docs/building-win-x64.md +++ b/docs/building-win-x64.md @@ -21,7 +21,6 @@ You will require **api_id** and **api_hash** to access the Telegram API servers. ## Install third party software * Download **Python 3.10** installer from [https://www.python.org/downloads/](https://www.python.org/downloads/) and install it with adding to PATH. -* Download **CMake 3.21 or later** installer from [https://cmake.org/download/](https://cmake.org/download/) and install it. * Download **Git** installer from [https://git-scm.com/download/win](https://git-scm.com/download/win) and install it. ## Clone source code and prepare libraries