Moved items highlighting to separate management module.

This commit is contained in:
23rd 2022-06-05 01:17:58 +03:00
parent 924780d8d8
commit ba7422805b
8 changed files with 198 additions and 164 deletions

View File

@ -728,6 +728,8 @@ PRIVATE
history/history_service.h
history/history_unread_things.cpp
history/history_unread_things.h
history/history_view_highlight_manager.cpp
history/history_view_highlight_manager.h
history/history_widget.cpp
history/history_widget.h
info/info_content_widget.cpp

View File

@ -3158,14 +3158,7 @@ void HistoryInner::elementStartStickerLoop(
crl::time HistoryInner::elementHighlightTime(
not_null<const HistoryItem*> item) {
const auto fullAnimMs = _widget->highlightStartTime(item);
if (fullAnimMs > 0) {
const auto now = crl::now();
if (fullAnimMs < now) {
return now - fullAnimMs;
}
}
return 0;
return _widget->highlightStartTime(item);
}
void HistoryInner::elementShowPollResults(

View File

@ -0,0 +1,118 @@
/*
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 "history/history_view_highlight_manager.h"
#include "data/data_session.h"
#include "history/history_item.h"
#include "history/view/history_view_element.h"
namespace HistoryView {
ElementHighlighter::ElementHighlighter(
not_null<Data::Session*> data,
ViewForItem viewForItem,
RepaintView repaintView)
: _data(data)
, _viewForItem(std::move(viewForItem))
, _repaintView(std::move(repaintView))
, _timer([=] { updateMessage(); }) {
}
void ElementHighlighter::enqueue(not_null<Element*> view) {
const auto item = view->data();
const auto fullId = item->fullId();
if (_queue.empty() && !_timer.isActive()) {
highlight(fullId);
} else if (_highlightedMessageId != fullId
&& !base::contains(_queue, fullId)) {
_queue.push_back(fullId);
checkNextHighlight();
}
}
void ElementHighlighter::checkNextHighlight() {
if (_timer.isActive()) {
return;
}
const auto nextHighlight = [&] {
while (!_queue.empty()) {
const auto fullId = _queue.front();
_queue.pop_front();
if (const auto item = _data->message(fullId)) {
if (_viewForItem(item)) {
return fullId;
}
}
}
return FullMsgId();
}();
if (!nextHighlight) {
return;
}
highlight(nextHighlight);
}
crl::time ElementHighlighter::elementTime(
not_null<const HistoryItem*> item) const {
if (item->fullId() == _highlightedMessageId) {
if (_timer.isActive()) {
return crl::now() - _highlightStart;
}
}
return crl::time(0);
}
void ElementHighlighter::highlight(FullMsgId itemId) {
if (const auto item = _data->message(itemId)) {
if (const auto view = _viewForItem(item)) {
_highlightStart = crl::now();
_highlightedMessageId = itemId;
_timer.callEach(AnimationTimerDelta);
repaintHighlightedItem(view);
}
}
}
void ElementHighlighter::repaintHighlightedItem(
not_null<const Element*> view) {
if (view->isHiddenByGroup()) {
if (const auto group = _data->groups().find(view->data())) {
if (const auto leader = _viewForItem(group->items.front())) {
if (!leader->isHiddenByGroup()) {
_repaintView(leader);
return;
}
}
}
}
_repaintView(view);
}
void ElementHighlighter::updateMessage() {
if (const auto item = _data->message(_highlightedMessageId)) {
if (const auto view = _viewForItem(item)) {
repaintHighlightedItem(view);
const auto duration = st::activeFadeInDuration
+ st::activeFadeOutDuration;
if (crl::now() - _highlightStart <= duration) {
return;
}
}
}
_timer.cancel();
_highlightedMessageId = FullMsgId();
checkNextHighlight();
}
void ElementHighlighter::clear() {
_highlightedMessageId = FullMsgId();
updateMessage();
}
} // namespace HistoryView

View File

@ -0,0 +1,54 @@
/*
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
#include "base/timer.h"
class HistoryItem;
namespace Data {
class Session;
} // namespace Data
namespace HistoryView {
class Element;
class ElementHighlighter final {
public:
using ViewForItem = Fn<Element*(const HistoryItem*)>;
using RepaintView = Fn<void(const Element*)>;
ElementHighlighter(
not_null<Data::Session*> data,
ViewForItem viewForItem,
RepaintView repaintView);
void enqueue(not_null<Element*> view);
void highlight(FullMsgId itemId);
void clear();
[[nodiscard]] crl::time elementTime(
not_null<const HistoryItem*> item) const;
private:
void checkNextHighlight();
void repaintHighlightedItem(not_null<const Element*> view);
void updateMessage();
const not_null<Data::Session*> _data;
const ViewForItem _viewForItem;
const RepaintView _repaintView;
FullMsgId _highlightedMessageId;
std::deque<FullMsgId> _queue;
base::Timer _timer;
crl::time _highlightStart = 0;
};
} // namespace HistoryView

View File

@ -277,6 +277,12 @@ HistoryWidget::HistoryWidget(
controller,
this)))
, _membersDropdownShowTimer([=] { showMembersDropdown(); })
, _highlighter(
&session().data(),
[=](const HistoryItem *item) { return item->mainView(); },
[=](const HistoryView::Element *view) {
session().data().requestViewRepaint(view);
})
, _saveDraftTimer([=] { saveDraft(); })
, _saveCloudDraftTimer([=] { saveCloudDraft(); })
, _topShadow(this) {
@ -357,8 +363,6 @@ HistoryWidget::HistoryWidget(
this,
[=] { chooseAttach(); }));
_highlightTimer.setCallback([this] { updateHighlightedMessage(); });
const auto rawTextEdit = _field->rawTextEdit().get();
rpl::merge(
_field->scrollTop().changes() | rpl::to_empty,
@ -1259,92 +1263,12 @@ void HistoryWidget::scrollToAnimationCallback(
void HistoryWidget::enqueueMessageHighlight(
not_null<HistoryView::Element*> view) {
auto enqueueMessageId = [this](MsgId universalId) {
if (_highlightQueue.empty() && !_highlightTimer.isActive()) {
highlightMessage(universalId);
} else if (_highlightedMessageId != universalId
&& !base::contains(_highlightQueue, universalId)) {
_highlightQueue.push_back(universalId);
checkNextHighlight();
}
};
const auto item = view->data();
if (item->history() == _history) {
enqueueMessageId(item->id);
} else if (item->history() == _migrated) {
enqueueMessageId(-item->id);
}
_highlighter.enqueue(view);
}
void HistoryWidget::highlightMessage(MsgId universalMessageId) {
_highlightStart = crl::now();
_highlightedMessageId = universalMessageId;
_highlightTimer.callEach(AnimationTimerDelta);
}
void HistoryWidget::checkNextHighlight() {
if (_highlightTimer.isActive()) {
return;
}
auto nextHighlight = [this] {
while (!_highlightQueue.empty()) {
auto msgId = _highlightQueue.front();
_highlightQueue.pop_front();
auto item = getItemFromHistoryOrMigrated(msgId);
if (item && item->mainView()) {
return msgId;
}
}
return MsgId();
}();
if (!nextHighlight) {
return;
}
highlightMessage(nextHighlight);
}
void HistoryWidget::updateHighlightedMessage() {
const auto item = getItemFromHistoryOrMigrated(_highlightedMessageId);
auto view = item ? item->mainView() : nullptr;
if (!view) {
return stopMessageHighlight();
}
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
if (crl::now() - _highlightStart > duration) {
return stopMessageHighlight();
}
if (const auto group = session().data().groups().find(view->data())) {
if (const auto leader = group->items.front()->mainView()) {
view = leader;
}
}
session().data().requestViewRepaint(view);
}
crl::time HistoryWidget::highlightStartTime(not_null<const HistoryItem*> item) const {
auto isHighlighted = [this](not_null<const HistoryItem*> item) {
if (item->id == _highlightedMessageId) {
return (item->history() == _history);
} else if (item->id == -_highlightedMessageId) {
return (item->history() == _migrated);
}
return false;
};
return (isHighlighted(item) && _highlightTimer.isActive())
? _highlightStart
: 0;
}
void HistoryWidget::stopMessageHighlight() {
_highlightTimer.cancel();
_highlightedMessageId = 0;
checkNextHighlight();
}
void HistoryWidget::clearHighlightMessages() {
_highlightQueue.clear();
stopMessageHighlight();
crl::time HistoryWidget::highlightStartTime(
not_null<const HistoryItem*> item) const {
return _highlighter.elementTime(item);
}
int HistoryWidget::itemTopForHighlight(
@ -2048,7 +1972,7 @@ void HistoryWidget::showHistory(
showAtMsgId = ShowAtTheEndMsgId;
}
clearHighlightMessages();
_highlighter.clear();
controller()->sendingAnimation().clear();
hideInfoTooltip(anim::type::instant);
if (_history) {
@ -6233,7 +6157,7 @@ bool HistoryWidget::replyToNextMessage() {
controller()->showPeerHistoryAtItem(next);
replyToMessage(next);
} else {
clearHighlightMessages();
_highlighter.clear();
cancelReply(false);
}
return true;

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "history/history_drag_area.h"
#include "history/history_view_highlight_manager.h"
#include "history/history.h"
#include "ui/widgets/tooltip.h"
#include "mainwidget.h"
@ -115,7 +116,6 @@ class TTLButton;
} // namespace Controls
} // namespace HistoryView
class DragArea;
class SendFilesBox;
class BotKeyboard;
class MessageField;
@ -420,12 +420,6 @@ private:
void supportInsertText(const QString &text);
void supportShareContact(Support::Contact contact);
void highlightMessage(MsgId universalMessageId);
void checkNextHighlight();
void updateHighlightedMessage();
void clearHighlightMessages();
void stopMessageHighlight();
auto computeSendButtonType() const;
void animationCallback();
@ -792,10 +786,7 @@ private:
Window::SlideDirection _showDirection;
QPixmap _cacheUnder, _cacheOver;
MsgId _highlightedMessageId = 0;
std::deque<MsgId> _highlightQueue;
base::Timer _highlightTimer;
crl::time _highlightStart = 0;
HistoryView::ElementHighlighter _highlighter;
crl::time _saveDraftStart = 0;
bool _saveDraftText = false;

View File

@ -283,7 +283,10 @@ ListWidget::ListWidget(
, _scrollDateCheck([this] { scrollDateCheck(); })
, _applyUpdatedScrollState([this] { applyUpdatedScrollState(); })
, _selectEnabled(_delegate->listAllowsMultiSelect())
, _highlightTimer([this] { updateHighlightedMessage(); }) {
, _highlighter(
&session().data(),
[=](const HistoryItem *item) { return viewForItem(item); },
[=](const Element *view) { repaintItem(view); }) {
setMouseTracking(true);
_scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); });
session().data().viewRepaintRequest(
@ -578,15 +581,7 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const {
}
void ListWidget::highlightMessage(FullMsgId itemId) {
if (const auto item = session().data().message(itemId)) {
if (const auto view = viewForItem(item)) {
_highlightStart = crl::now();
_highlightedMessageId = itemId;
_highlightTimer.callEach(AnimationTimerDelta);
repaintHighlightedItem(view);
}
}
_highlighter.highlight(itemId);
}
void ListWidget::showAroundPosition(
@ -598,39 +593,6 @@ void ListWidget::showAroundPosition(
refreshViewer();
}
void ListWidget::repaintHighlightedItem(not_null<const Element*> view) {
if (view->isHiddenByGroup()) {
if (const auto group = session().data().groups().find(view->data())) {
if (const auto leader = viewForItem(group->items.front())) {
if (!leader->isHiddenByGroup()) {
repaintItem(leader);
return;
}
}
}
}
repaintItem(view);
}
void ListWidget::updateHighlightedMessage() {
if (const auto item = session().data().message(_highlightedMessageId)) {
if (const auto view = viewForItem(item)) {
repaintHighlightedItem(view);
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
if (crl::now() - _highlightStart <= duration) {
return;
}
}
}
_highlightTimer.cancel();
_highlightedMessageId = FullMsgId();
}
void ListWidget::clearHighlightedMessage() {
_highlightedMessageId = FullMsgId();
updateHighlightedMessage();
}
void ListWidget::checkUnreadBarCreation() {
if (!_bar.element) {
if (auto data = _delegate->listMessagesBar(_items); data.bar.element) {
@ -1437,12 +1399,7 @@ bool ListWidget::elementUnderCursor(
crl::time ListWidget::elementHighlightTime(
not_null<const HistoryItem*> item) {
if (item->fullId() == _highlightedMessageId) {
if (_highlightTimer.isActive()) {
return crl::now() - _highlightStart;
}
}
return crl::time(0);
return _highlighter.elementTime(item);
}
bool ListWidget::elementInSelectionMode() {
@ -3266,7 +3223,7 @@ void ListWidget::replyNextMessage(FullMsgId fullId, bool next) {
_requestedToShowMessage.fire_copy(newFullId);
} else {
replyToMessageRequestNotify(FullMsgId());
clearHighlightedMessage();
_highlighter.clear();
}
};
const auto replyFirst = [&] {

View File

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/sender.h"
#include "data/data_messages.h"
#include "history/view/history_view_element.h"
#include "history/history_view_highlight_manager.h"
namespace Main {
class Session;
@ -405,7 +406,6 @@ private:
int itemTop(not_null<const Element*> view) const;
void repaintItem(FullMsgId itemId);
void repaintItem(const Element *view);
void repaintHighlightedItem(not_null<const Element*> view);
void resizeItem(not_null<Element*> view);
void refreshItem(not_null<const Element*> view);
void itemRemoved(not_null<const HistoryItem*> item);
@ -516,9 +516,6 @@ private:
void startMessageSendingAnimation(not_null<HistoryItem*> item);
void updateHighlightedMessage();
void clearHighlightedMessage();
// This function finds all history items that are displayed and calls template method
// for each found message (in given direction) in the passed history with passed top offset.
//
@ -638,9 +635,7 @@ private:
QPoint _trippleClickPoint;
crl::time _trippleClickStartTime = 0;
crl::time _highlightStart = 0;
FullMsgId _highlightedMessageId;
base::Timer _highlightTimer;
ElementHighlighter _highlighter;
Ui::Animations::Simple _spoilerOpacity;