init
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
Close stale issues and PRs / stale (push) Has been cancelled
This commit is contained in:
277
Telegram/SourceFiles/history/history_view_highlight_manager.cpp
Normal file
277
Telegram/SourceFiles/history/history_view_highlight_manager.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
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.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/view/history_view_element.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
|
||||
namespace HistoryView {
|
||||
|
||||
ElementHighlighter::ElementHighlighter(
|
||||
not_null<Data::Session*> data,
|
||||
ViewForItem viewForItem,
|
||||
RepaintView repaintView)
|
||||
: _data(data)
|
||||
, _viewForItem(std::move(viewForItem))
|
||||
, _repaintView(std::move(repaintView))
|
||||
, _animation(*this) {
|
||||
}
|
||||
|
||||
void ElementHighlighter::enqueue(const SelectedQuote "e) {
|
||||
const auto data = computeHighlight(quote);
|
||||
if (_queue.empty() && !_animation.animating()) {
|
||||
highlight(data);
|
||||
} else if (_highlighted != data && !base::contains(_queue, data)) {
|
||||
_queue.push_back(data);
|
||||
checkNextHighlight();
|
||||
}
|
||||
}
|
||||
|
||||
void ElementHighlighter::highlight(const SelectedQuote "e) {
|
||||
highlight(computeHighlight(quote));
|
||||
}
|
||||
|
||||
void ElementHighlighter::checkNextHighlight() {
|
||||
if (_animation.animating()) {
|
||||
return;
|
||||
}
|
||||
const auto next = [&] {
|
||||
while (!_queue.empty()) {
|
||||
const auto highlight = _queue.front();
|
||||
_queue.pop_front();
|
||||
if (const auto item = _data->message(highlight.itemId)) {
|
||||
if (_viewForItem(item)) {
|
||||
return highlight;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Highlight();
|
||||
}();
|
||||
if (next) {
|
||||
highlight(next);
|
||||
}
|
||||
}
|
||||
|
||||
Ui::ChatPaintHighlight ElementHighlighter::state(
|
||||
not_null<const HistoryItem*> item) const {
|
||||
if (item->fullId() == _highlighted.itemId) {
|
||||
auto result = _animation.state();
|
||||
result.range = _highlighted.part;
|
||||
result.todoItemId = _highlighted.todoListId;
|
||||
return result;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
ElementHighlighter::Highlight ElementHighlighter::computeHighlight(
|
||||
const SelectedQuote "e) {
|
||||
Assert(quote.item != nullptr);
|
||||
|
||||
const auto item = not_null(quote.item);
|
||||
const auto owner = &item->history()->owner();
|
||||
if (const auto group = owner->groups().find(item)) {
|
||||
const auto leader = group->items.front();
|
||||
const auto leaderId = leader->fullId();
|
||||
const auto i = ranges::find(group->items, item);
|
||||
if (i != end(group->items)) {
|
||||
const auto index = int(i - begin(group->items));
|
||||
if (quote.highlight.empty()) {
|
||||
return { leaderId, AddGroupItemSelection({}, index) };
|
||||
} else if (const auto leaderView = _viewForItem(leader)) {
|
||||
return {
|
||||
leaderId,
|
||||
leaderView->selectionFromQuote(quote),
|
||||
quote.highlight.todoItemId,
|
||||
};
|
||||
}
|
||||
}
|
||||
return { leaderId, {}, quote.highlight.todoItemId };
|
||||
} else if (quote.highlight.quote.empty()) {
|
||||
return { item->fullId(), {}, quote.highlight.todoItemId };
|
||||
} else if (const auto view = _viewForItem(item)) {
|
||||
return {
|
||||
item->fullId(),
|
||||
view->selectionFromQuote(quote),
|
||||
quote.highlight.todoItemId,
|
||||
};
|
||||
}
|
||||
return { item->fullId(), {}, quote.highlight.todoItemId };
|
||||
}
|
||||
|
||||
void ElementHighlighter::highlight(Highlight data) {
|
||||
if (const auto item = _data->message(data.itemId)) {
|
||||
if (const auto view = _viewForItem(item)) {
|
||||
if (_highlighted && _highlighted.itemId != data.itemId) {
|
||||
if (const auto was = _data->message(_highlighted.itemId)) {
|
||||
if (const auto view = _viewForItem(was)) {
|
||||
repaintHighlightedItem(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
_highlighted = data;
|
||||
_animation.start((!data.part.empty() || data.todoListId)
|
||||
&& !IsSubGroupSelection(data.part));
|
||||
|
||||
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(_highlighted.itemId)) {
|
||||
if (const auto view = _viewForItem(item)) {
|
||||
repaintHighlightedItem(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ElementHighlighter::clear() {
|
||||
_animation.cancel();
|
||||
_highlighted = {};
|
||||
_lastHighlightedMessageId = FullMsgId();
|
||||
_queue.clear();
|
||||
}
|
||||
|
||||
ElementHighlighter::AnimationManager::AnimationManager(
|
||||
ElementHighlighter &parent)
|
||||
: _parent(parent) {
|
||||
}
|
||||
|
||||
bool ElementHighlighter::AnimationManager::animating() const {
|
||||
if (_timer && _timer->isActive()) {
|
||||
return true;
|
||||
} else if (!anim::Disabled()) {
|
||||
return _simple.animating();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Ui::ChatPaintHighlight ElementHighlighter::AnimationManager::state() const {
|
||||
if (anim::Disabled()) {
|
||||
return {
|
||||
.opacity = !_timer ? 0. : 1.,
|
||||
.collapsion = !_timer ? 0. : _fadingOut ? 1. : 0.,
|
||||
};
|
||||
}
|
||||
return {
|
||||
.opacity = ((!_fadingOut && _collapsing)
|
||||
? 1.
|
||||
: _simple.value(_fadingOut ? 0. : 1.)),
|
||||
.collapsion = ((!_withTextPart || !_collapsing)
|
||||
? 0.
|
||||
: _fadingOut
|
||||
? 1.
|
||||
: _simple.value(1.)),
|
||||
};
|
||||
}
|
||||
|
||||
MsgId ElementHighlighter::latestSingleHighlightedMsgId() const {
|
||||
return _highlighted.itemId
|
||||
? _highlighted.itemId.msg
|
||||
: _lastHighlightedMessageId.msg;
|
||||
}
|
||||
|
||||
void ElementHighlighter::AnimationManager::start(bool withTextPart) {
|
||||
_withTextPart = withTextPart;
|
||||
const auto finish = [=] {
|
||||
cancel();
|
||||
_parent._lastHighlightedMessageId = base::take(
|
||||
_parent._highlighted.itemId);
|
||||
_parent.checkNextHighlight();
|
||||
};
|
||||
cancel();
|
||||
if (anim::Disabled()) {
|
||||
_timer.emplace([=] {
|
||||
_parent.updateMessage();
|
||||
if (_withTextPart && !_fadingOut) {
|
||||
_fadingOut = true;
|
||||
_timer->callOnce(st::activeFadeOutDuration);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
_timer->callOnce(_withTextPart
|
||||
? st::activeFadeInDuration
|
||||
: st::activeFadeOutDuration);
|
||||
_parent.updateMessage();
|
||||
} else {
|
||||
_simple.start(
|
||||
[=](float64 value) {
|
||||
_parent.updateMessage();
|
||||
if (value == 1.) {
|
||||
if (_withTextPart) {
|
||||
_timer.emplace([=] {
|
||||
_parent.updateMessage();
|
||||
if (_collapsing) {
|
||||
_fadingOut = true;
|
||||
} else {
|
||||
_collapsing = true;
|
||||
}
|
||||
_simple.start([=](float64 value) {
|
||||
_parent.updateMessage();
|
||||
if (_fadingOut && value == 0.) {
|
||||
finish();
|
||||
} else if (!_fadingOut && value == 1.) {
|
||||
_timer->callOnce(
|
||||
st::activeFadeOutDuration);
|
||||
}
|
||||
},
|
||||
_fadingOut ? 1. : 0.,
|
||||
_fadingOut ? 0. : 1.,
|
||||
(_fadingOut
|
||||
? st::activeFadeInDuration
|
||||
: st::fadeWrapDuration));
|
||||
});
|
||||
_timer->callOnce(st::activeFadeInDuration);
|
||||
} else {
|
||||
_fadingOut = true;
|
||||
_simple.start([=](float64 value) {
|
||||
_parent.updateMessage();
|
||||
if (value == 0.) {
|
||||
finish();
|
||||
}
|
||||
},
|
||||
1.,
|
||||
0.,
|
||||
st::activeFadeOutDuration);
|
||||
}
|
||||
}
|
||||
},
|
||||
0.,
|
||||
1.,
|
||||
st::activeFadeInDuration);
|
||||
}
|
||||
}
|
||||
|
||||
void ElementHighlighter::AnimationManager::cancel() {
|
||||
_simple.stop();
|
||||
_timer.reset();
|
||||
_fadingOut = false;
|
||||
_collapsed = false;
|
||||
_collapsing = false;
|
||||
}
|
||||
|
||||
} // namespace HistoryView
|
||||
Reference in New Issue
Block a user