mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +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(
|
void HistoryWidget::startMessageSendingAnimation(
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
auto &sendingAnimation = controller()->sendingAnimation();
|
auto &sendingAnimation = controller()->sendingAnimation();
|
||||||
if (!sendingAnimation.hasLocalMessage(item->fullId().msg)
|
if (!sendingAnimation.checkExpectedType(item)) {
|
||||||
|| !sendingAnimation.checkExpectedType(item)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Assert(item->mainView() != nullptr);
|
Assert(item->mainView() != nullptr);
|
||||||
|
@ -6257,14 +6256,16 @@ void HistoryWidget::startMessageSendingAnimation(
|
||||||
geometryValue() | rpl::to_empty,
|
geometryValue() | rpl::to_empty,
|
||||||
_scroll->geometryValue() | rpl::to_empty,
|
_scroll->geometryValue() | rpl::to_empty,
|
||||||
_list->geometryValue() | rpl::to_empty
|
_list->geometryValue() | rpl::to_empty
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=]() -> std::optional<QPoint> {
|
||||||
const auto view = item->mainView();
|
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())
|
const auto additional = (_list->height() == _scroll->height())
|
||||||
? view->height()
|
? view->height()
|
||||||
: 0;
|
: 0;
|
||||||
return _list->mapToGlobal(QPoint(
|
return _list->mapToGlobal(QPoint(0, top - additional));
|
||||||
0,
|
|
||||||
_list->itemTop(view) - additional));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sendingAnimation.startAnimation({
|
sendingAnimation.startAnimation({
|
||||||
|
|
|
@ -1839,16 +1839,18 @@ void ListWidget::startItemRevealAnimations() {
|
||||||
void ListWidget::startMessageSendingAnimation(
|
void ListWidget::startMessageSendingAnimation(
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
auto &sendingAnimation = controller()->sendingAnimation();
|
auto &sendingAnimation = controller()->sendingAnimation();
|
||||||
if (!sendingAnimation.hasLocalMessage(item->fullId().msg)
|
if (!sendingAnimation.checkExpectedType(item)) {
|
||||||
|| !sendingAnimation.checkExpectedType(item)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto globalEndTopLeft = rpl::merge(
|
auto globalEndTopLeft = rpl::merge(
|
||||||
session().data().newItemAdded() | rpl::to_empty,
|
session().data().newItemAdded() | rpl::to_empty,
|
||||||
geometryValue() | rpl::to_empty
|
geometryValue() | rpl::to_empty
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=]() -> std::optional<QPoint> {
|
||||||
const auto view = viewForItem(item);
|
const auto view = viewForItem(item);
|
||||||
|
if (!view) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
const auto additional = !_visibleTop ? view->height() : 0;
|
const auto additional = !_visibleTop ? view->height() : 0;
|
||||||
return mapToGlobal(QPoint(0, itemTop(view) - additional));
|
return mapToGlobal(QPoint(0, itemTop(view) - additional));
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
Content(
|
Content(
|
||||||
not_null<RpWidget*> parent,
|
not_null<RpWidget*> parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const MessageSendingAnimationFrom &fromInfo,
|
MessageSendingAnimationFrom &&fromInfo,
|
||||||
MessageSendingAnimationController::SendingInfoTo &&to);
|
MessageSendingAnimationController::SendingInfoTo &&to);
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> destroyRequests() const;
|
[[nodiscard]] rpl::producer<> destroyRequests() const;
|
||||||
|
@ -79,7 +79,7 @@ private:
|
||||||
Content::Content(
|
Content::Content(
|
||||||
not_null<RpWidget*> parent,
|
not_null<RpWidget*> parent,
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const MessageSendingAnimationFrom &fromInfo,
|
MessageSendingAnimationFrom &&fromInfo,
|
||||||
MessageSendingAnimationController::SendingInfoTo &&to)
|
MessageSendingAnimationController::SendingInfoTo &&to)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _controller(controller)
|
, _controller(controller)
|
||||||
|
@ -98,8 +98,12 @@ Content::Content(
|
||||||
base::take(
|
base::take(
|
||||||
_toInfo.globalEndTopLeft
|
_toInfo.globalEndTopLeft
|
||||||
) | rpl::distinct_until_changed(
|
) | rpl::distinct_until_changed(
|
||||||
) | rpl::start_with_next([=](const QPoint &p) {
|
) | rpl::start_with_next([=](const std::optional<QPoint> &p) {
|
||||||
_to = parent->mapFromGlobal(p);
|
if (p) {
|
||||||
|
_to = parent->mapFromGlobal(*p);
|
||||||
|
} else {
|
||||||
|
_destroyRequests.fire({});
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
_controller->session().downloaderTaskFinished(
|
_controller->session().downloaderTaskFinished(
|
||||||
|
@ -366,6 +370,20 @@ void Content::createBubble() {
|
||||||
MessageSendingAnimationController::MessageSendingAnimationController(
|
MessageSendingAnimationController::MessageSendingAnimationController(
|
||||||
not_null<Window::SessionController*> controller)
|
not_null<Window::SessionController*> controller)
|
||||||
: _controller(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(
|
void MessageSendingAnimationController::appendSending(
|
||||||
|
@ -389,26 +407,23 @@ void MessageSendingAnimationController::startAnimation(SendingInfoTo &&to) {
|
||||||
if (it == end(_itemSendPending)) {
|
if (it == end(_itemSendPending)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto msg = it->first;
|
auto from = std::move(it->second);
|
||||||
|
_itemSendPending.erase(it);
|
||||||
|
|
||||||
auto content = base::make_unique_q<Content>(
|
auto content = base::make_unique_q<Content>(
|
||||||
container,
|
container,
|
||||||
_controller,
|
_controller,
|
||||||
it->second,
|
std::move(from),
|
||||||
std::move(to));
|
std::move(to));
|
||||||
|
|
||||||
content->destroyRequests(
|
content->destroyRequests(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_itemSendPending.erase(msg);
|
|
||||||
_processing.erase(item);
|
_processing.erase(item);
|
||||||
}, content->lifetime());
|
}, content->lifetime());
|
||||||
|
|
||||||
_processing.emplace(item, std::move(content));
|
_processing.emplace(item, std::move(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageSendingAnimationController::hasLocalMessage(MsgId msgId) const {
|
|
||||||
return _itemSendPending.contains(msgId);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MessageSendingAnimationController::hasAnimatedMessage(
|
bool MessageSendingAnimationController::hasAnimatedMessage(
|
||||||
not_null<HistoryItem*> item) const {
|
not_null<HistoryItem*> item) const {
|
||||||
return _processing.contains(item);
|
return _processing.contains(item);
|
||||||
|
@ -421,7 +436,7 @@ void MessageSendingAnimationController::clear() {
|
||||||
|
|
||||||
bool MessageSendingAnimationController::checkExpectedType(
|
bool MessageSendingAnimationController::checkExpectedType(
|
||||||
not_null<HistoryItem*> item) {
|
not_null<HistoryItem*> item) {
|
||||||
const auto it = _itemSendPending.find(item->fullId().msg);
|
const auto it = _itemSendPending.find(item->id);
|
||||||
if (it == end(_itemSendPending)) {
|
if (it == end(_itemSendPending)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
not_null<Window::SessionController*> controller);
|
not_null<Window::SessionController*> controller);
|
||||||
|
|
||||||
struct SendingInfoTo {
|
struct SendingInfoTo {
|
||||||
rpl::producer<QPoint> globalEndTopLeft;
|
rpl::producer<std::optional<QPoint>> globalEndTopLeft;
|
||||||
Fn<HistoryView::Element*()> view;
|
Fn<HistoryView::Element*()> view;
|
||||||
Fn<Ui::ChatPaintContext()> paintContext;
|
Fn<Ui::ChatPaintContext()> paintContext;
|
||||||
};
|
};
|
||||||
|
@ -37,13 +37,13 @@ public:
|
||||||
void appendSending(MessageSendingAnimationFrom from);
|
void appendSending(MessageSendingAnimationFrom from);
|
||||||
void startAnimation(SendingInfoTo &&to);
|
void startAnimation(SendingInfoTo &&to);
|
||||||
|
|
||||||
[[nodiscard]] bool hasLocalMessage(MsgId msgId) const;
|
|
||||||
[[nodiscard]] bool hasAnimatedMessage(not_null<HistoryItem*> item) const;
|
[[nodiscard]] bool hasAnimatedMessage(not_null<HistoryItem*> item) const;
|
||||||
[[nodiscard]] bool checkExpectedType(not_null<HistoryItem*> item);
|
[[nodiscard]] bool checkExpectedType(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void subscribeToDestructions();
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _controller;
|
const not_null<Window::SessionController*> _controller;
|
||||||
base::flat_map<MsgId, MessageSendingAnimationFrom> _itemSendPending;
|
base::flat_map<MsgId, MessageSendingAnimationFrom> _itemSendPending;
|
||||||
|
@ -52,6 +52,8 @@ private:
|
||||||
not_null<HistoryItem*>,
|
not_null<HistoryItem*>,
|
||||||
base::unique_qptr<RpWidget>> _processing;
|
base::unique_qptr<RpWidget>> _processing;
|
||||||
|
|
||||||
|
rpl::lifetime _lifetime;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
Loading…
Add table
Reference in a new issue