mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Fix rare crashes in message sending animations.
This commit is contained in:
parent
1da9df690f
commit
8ab118a8e9
4 changed files with 43 additions and 23 deletions
|
@ -6244,8 +6244,7 @@ void HistoryWidget::startItemRevealAnimations() {
|
|||
void HistoryWidget::startMessageSendingAnimation(
|
||||
not_null<HistoryItem*> 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<QPoint> {
|
||||
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({
|
||||
|
|
|
@ -1839,16 +1839,18 @@ void ListWidget::startItemRevealAnimations() {
|
|||
void ListWidget::startMessageSendingAnimation(
|
||||
not_null<HistoryItem*> 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<QPoint> {
|
||||
const auto view = viewForItem(item);
|
||||
if (!view) {
|
||||
return std::nullopt;
|
||||
}
|
||||
const auto additional = !_visibleTop ? view->height() : 0;
|
||||
return mapToGlobal(QPoint(0, itemTop(view) - additional));
|
||||
});
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
Content(
|
||||
not_null<RpWidget*> parent,
|
||||
not_null<Window::SessionController*> controller,
|
||||
const MessageSendingAnimationFrom &fromInfo,
|
||||
MessageSendingAnimationFrom &&fromInfo,
|
||||
MessageSendingAnimationController::SendingInfoTo &&to);
|
||||
|
||||
[[nodiscard]] rpl::producer<> destroyRequests() const;
|
||||
|
@ -79,7 +79,7 @@ private:
|
|||
Content::Content(
|
||||
not_null<RpWidget*> parent,
|
||||
not_null<Window::SessionController*> 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<QPoint> &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<Window::SessionController*> 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<const HistoryItem*> 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<Content>(
|
||||
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<HistoryItem*> item) const {
|
||||
return _processing.contains(item);
|
||||
|
@ -421,7 +436,7 @@ void MessageSendingAnimationController::clear() {
|
|||
|
||||
bool MessageSendingAnimationController::checkExpectedType(
|
||||
not_null<HistoryItem*> item) {
|
||||
const auto it = _itemSendPending.find(item->fullId().msg);
|
||||
const auto it = _itemSendPending.find(item->id);
|
||||
if (it == end(_itemSendPending)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
not_null<Window::SessionController*> controller);
|
||||
|
||||
struct SendingInfoTo {
|
||||
rpl::producer<QPoint> globalEndTopLeft;
|
||||
rpl::producer<std::optional<QPoint>> globalEndTopLeft;
|
||||
Fn<HistoryView::Element*()> view;
|
||||
Fn<Ui::ChatPaintContext()> 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<HistoryItem*> item) const;
|
||||
[[nodiscard]] bool checkExpectedType(not_null<HistoryItem*> item);
|
||||
|
||||
void clear();
|
||||
|
||||
private:
|
||||
void subscribeToDestructions();
|
||||
|
||||
const not_null<Window::SessionController*> _controller;
|
||||
base::flat_map<MsgId, MessageSendingAnimationFrom> _itemSendPending;
|
||||
|
@ -52,6 +52,8 @@ private:
|
|||
not_null<HistoryItem*>,
|
||||
base::unique_qptr<RpWidget>> _processing;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Ui
|
||||
|
|
Loading…
Add table
Reference in a new issue