diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index 79994f61f..8d2dff310 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -6244,8 +6244,7 @@ void HistoryWidget::startItemRevealAnimations() { void HistoryWidget::startMessageSendingAnimation( not_null item) { auto &sendingAnimation = controller()->sendingAnimation(); - if (!sendingAnimation.hasLocalMessage(item->fullId().msg) - || !sendingAnimation.checkExpectedType(item)) { + if (!sendingAnimation.checkExpectedType(item)) { return; } Assert(item->mainView() != nullptr); @@ -6257,14 +6256,16 @@ void HistoryWidget::startMessageSendingAnimation( geometryValue() | rpl::to_empty, _scroll->geometryValue() | rpl::to_empty, _list->geometryValue() | rpl::to_empty - ) | rpl::map([=] { + ) | rpl::map([=]() -> std::optional { const auto view = item->mainView(); + const auto top = view ? _list->itemTop(view) : -1; + if (top < 0) { + return std::nullopt; + } const auto additional = (_list->height() == _scroll->height()) ? view->height() : 0; - return _list->mapToGlobal(QPoint( - 0, - _list->itemTop(view) - additional)); + return _list->mapToGlobal(QPoint(0, top - additional)); }); sendingAnimation.startAnimation({ diff --git a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp index fb8d99130..23b7c0be3 100644 --- a/Telegram/SourceFiles/history/view/history_view_list_widget.cpp +++ b/Telegram/SourceFiles/history/view/history_view_list_widget.cpp @@ -1839,16 +1839,18 @@ void ListWidget::startItemRevealAnimations() { void ListWidget::startMessageSendingAnimation( not_null item) { auto &sendingAnimation = controller()->sendingAnimation(); - if (!sendingAnimation.hasLocalMessage(item->fullId().msg) - || !sendingAnimation.checkExpectedType(item)) { + if (!sendingAnimation.checkExpectedType(item)) { return; } auto globalEndTopLeft = rpl::merge( session().data().newItemAdded() | rpl::to_empty, geometryValue() | rpl::to_empty - ) | rpl::map([=] { + ) | rpl::map([=]() -> std::optional { const auto view = viewForItem(item); + if (!view) { + return std::nullopt; + } const auto additional = !_visibleTop ? view->height() : 0; return mapToGlobal(QPoint(0, itemTop(view) - additional)); }); diff --git a/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.cpp b/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.cpp index 84d98f521..552f46412 100644 --- a/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.cpp +++ b/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.cpp @@ -39,7 +39,7 @@ public: Content( not_null parent, not_null controller, - const MessageSendingAnimationFrom &fromInfo, + MessageSendingAnimationFrom &&fromInfo, MessageSendingAnimationController::SendingInfoTo &&to); [[nodiscard]] rpl::producer<> destroyRequests() const; @@ -79,7 +79,7 @@ private: Content::Content( not_null parent, not_null controller, - const MessageSendingAnimationFrom &fromInfo, + MessageSendingAnimationFrom &&fromInfo, MessageSendingAnimationController::SendingInfoTo &&to) : RpWidget(parent) , _controller(controller) @@ -98,8 +98,12 @@ Content::Content( base::take( _toInfo.globalEndTopLeft ) | rpl::distinct_until_changed( - ) | rpl::start_with_next([=](const QPoint &p) { - _to = parent->mapFromGlobal(p); + ) | rpl::start_with_next([=](const std::optional &p) { + if (p) { + _to = parent->mapFromGlobal(*p); + } else { + _destroyRequests.fire({}); + } }, lifetime()); _controller->session().downloaderTaskFinished( @@ -366,6 +370,20 @@ void Content::createBubble() { MessageSendingAnimationController::MessageSendingAnimationController( not_null controller) : _controller(controller) { + subscribeToDestructions(); +} + +void MessageSendingAnimationController::subscribeToDestructions() { + _controller->session().data().itemIdChanged( + ) | rpl::start_with_next([=](Data::Session::IdChange change) { + _itemSendPending.remove(change.oldId); + }, _lifetime); + + _controller->session().data().itemRemoved( + ) | rpl::start_with_next([=](not_null item) { + _itemSendPending.remove(item->id); + _processing.remove(item); + }, _lifetime); } void MessageSendingAnimationController::appendSending( @@ -389,26 +407,23 @@ void MessageSendingAnimationController::startAnimation(SendingInfoTo &&to) { if (it == end(_itemSendPending)) { return; } - const auto msg = it->first; + auto from = std::move(it->second); + _itemSendPending.erase(it); auto content = base::make_unique_q( container, _controller, - it->second, + std::move(from), std::move(to)); + content->destroyRequests( ) | rpl::start_with_next([=] { - _itemSendPending.erase(msg); _processing.erase(item); }, content->lifetime()); _processing.emplace(item, std::move(content)); } -bool MessageSendingAnimationController::hasLocalMessage(MsgId msgId) const { - return _itemSendPending.contains(msgId); -} - bool MessageSendingAnimationController::hasAnimatedMessage( not_null item) const { return _processing.contains(item); @@ -421,7 +436,7 @@ void MessageSendingAnimationController::clear() { bool MessageSendingAnimationController::checkExpectedType( not_null item) { - const auto it = _itemSendPending.find(item->fullId().msg); + const auto it = _itemSendPending.find(item->id); if (it == end(_itemSendPending)) { return false; } diff --git a/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.h b/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.h index 92bb9a915..8250e778a 100644 --- a/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.h +++ b/Telegram/SourceFiles/ui/effects/message_sending_animation_controller.h @@ -29,7 +29,7 @@ public: not_null controller); struct SendingInfoTo { - rpl::producer globalEndTopLeft; + rpl::producer> globalEndTopLeft; Fn view; Fn paintContext; }; @@ -37,13 +37,13 @@ public: void appendSending(MessageSendingAnimationFrom from); void startAnimation(SendingInfoTo &&to); - [[nodiscard]] bool hasLocalMessage(MsgId msgId) const; [[nodiscard]] bool hasAnimatedMessage(not_null item) const; [[nodiscard]] bool checkExpectedType(not_null item); void clear(); private: + void subscribeToDestructions(); const not_null _controller; base::flat_map _itemSendPending; @@ -52,6 +52,8 @@ private: not_null, base::unique_qptr> _processing; + rpl::lifetime _lifetime; + }; } // namespace Ui