Highlight found messages in feed.

This commit is contained in:
John Preston 2018-02-16 20:59:35 +03:00
parent 07528be1e6
commit 351a423337
13 changed files with 145 additions and 60 deletions

View File

@ -508,6 +508,10 @@ void InnerWidget::elementAnimationAutoplayAsync(
}); });
} }
TimeMs InnerWidget::elementHighlightTime(
not_null<const HistoryView::Element*> element) {
return TimeMs(0);
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) { void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter)); memento->setFilter(std::move(_filter));

View File

@ -85,6 +85,8 @@ public:
not_null<const HistoryView::Element*> view) override; not_null<const HistoryView::Element*> view) override;
void elementAnimationAutoplayAsync( void elementAnimationAutoplayAsync(
not_null<const HistoryView::Element*> view) override; not_null<const HistoryView::Element*> view) override;
TimeMs elementHighlightTime(
not_null<const HistoryView::Element*> element) override;
~InnerWidget(); ~InnerWidget();

View File

@ -159,7 +159,11 @@ void Widget::scrollDownClicked() {
} }
void Widget::showAtPosition(Data::MessagePosition position) { void Widget::showAtPosition(Data::MessagePosition position) {
if (!showAtPositionNow(position)) { if (showAtPositionNow(position)) {
if (const auto highlight = base::take(_highlightMessageId)) {
_inner->highlightMessage(highlight);
}
} else {
_nextAnimatedScrollPosition = position; _nextAnimatedScrollPosition = position;
_nextAnimatedScrollDelta = _inner->isBelowPosition(position) _nextAnimatedScrollDelta = _inner->isBelowPosition(position)
? -_scroll->height() ? -_scroll->height()
@ -424,6 +428,9 @@ void Widget::listContentRefreshed() {
position, position,
_nextAnimatedScrollDelta, _nextAnimatedScrollDelta,
HistoryView::ListWidget::AnimatedScroll::Part); HistoryView::ListWidget::AnimatedScroll::Part);
if (const auto highlight = base::take(_highlightMessageId)) {
_inner->highlightMessage(highlight);
}
} }
} }
@ -447,7 +454,7 @@ void Widget::restoreState(not_null<Memento*> memento) {
_undefinedAroundPosition = !list->aroundPosition(); _undefinedAroundPosition = !list->aroundPosition();
_inner->restoreState(memento->list()); _inner->restoreState(memento->list());
if (const auto position = memento->position()) { if (const auto position = memento->position()) {
_currentMessageId = position.fullId; _currentMessageId = _highlightMessageId = position.fullId;
showAtPosition(position); showAtPosition(position);
} }
} }

View File

@ -129,6 +129,7 @@ private:
std::unique_ptr<HistoryView::Element> _emptyTextView; std::unique_ptr<HistoryView::Element> _emptyTextView;
FullMsgId _currentMessageId; FullMsgId _currentMessageId;
FullMsgId _highlightMessageId;
base::optional<Data::MessagePosition> _nextAnimatedScrollPosition; base::optional<Data::MessagePosition> _nextAnimatedScrollPosition;
int _nextAnimatedScrollDelta = 0; int _nextAnimatedScrollDelta = 0;

View File

@ -3006,6 +3006,18 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
} }
}); });
} }
TimeMs elementHighlightTime(
not_null<const HistoryView::Element*> view) override {
const auto fullAnimMs = App::main()->highlightStartTime(
view->data());
if (fullAnimMs > 0) {
const auto now = getms();
if (fullAnimMs < now) {
return now - fullAnimMs;
}
}
return TimeMs(0);
}
}; };

View File

@ -174,26 +174,34 @@ void Element::setY(int y) {
_y = y; _y = y;
} }
int Element::marginTop() const { void Element::paintHighlight(
const auto item = data(); Painter &p,
auto result = 0; int geometryHeight) const {
if (!isHidden()) { const auto animms = delegate()->elementHighlightTime(this);
if (isAttachedToPrevious()) { if (!animms
result += st::msgMarginTopAttached; || animms >= st::activeFadeInDuration + st::activeFadeOutDuration) {
} else { return;
result += st::msgMargin.top();
}
} }
result += displayedDateHeight();
if (const auto bar = Get<UnreadBar>()) {
result += bar->height();
}
return result;
}
int Element::marginBottom() const { const auto top = marginTop();
const auto item = data(); const auto bottom = marginBottom();
return isHidden() ? 0 : st::msgMargin.bottom(); const auto fill = qMin(top, bottom);
const auto skiptop = top - fill;
const auto fillheight = fill + geometryHeight + fill;
const auto dt = (animms > st::activeFadeInDuration)
? (1. - (animms - st::activeFadeInDuration)
/ float64(st::activeFadeOutDuration))
: (animms / float64(st::activeFadeInDuration));
const auto o = p.opacity();
p.setOpacity(o * dt);
p.fillRect(
0,
skiptop,
width(),
fillheight,
st::defaultTextPalette.selectOverlay);
p.setOpacity(o);
} }
bool Element::isUnderCursor() const { bool Element::isUnderCursor() const {

View File

@ -42,6 +42,8 @@ public:
virtual bool elementUnderCursor(not_null<const Element*> view) = 0; virtual bool elementUnderCursor(not_null<const Element*> view) = 0;
virtual void elementAnimationAutoplayAsync( virtual void elementAnimationAutoplayAsync(
not_null<const Element*> element) = 0; not_null<const Element*> element) = 0;
virtual TimeMs elementHighlightTime(
not_null<const Element*> element) = 0;
}; };
@ -126,8 +128,9 @@ public:
int y() const; int y() const;
void setY(int y); void setY(int y);
int marginTop() const; virtual int marginTop() const = 0;
int marginBottom() const; virtual int marginBottom() const = 0;
void setPendingResize(); void setPendingResize();
bool pendingResize() const; bool pendingResize() const;
bool isUnderCursor() const; bool isUnderCursor() const;
@ -242,8 +245,9 @@ public:
virtual ~Element(); virtual ~Element();
protected: protected:
void setInitialSize(int maxWidth, int minHeight); void paintHighlight(
void setCurrentSize(int width, int height); Painter &p,
int geometryHeight) const;
private: private:
// This should be called only from previousInBlocksChanged() // This should be called only from previousInBlocksChanged()

View File

@ -239,7 +239,8 @@ ListWidget::ListWidget(
, _itemAverageHeight(itemMinimalHeight()) , _itemAverageHeight(itemMinimalHeight())
, _scrollDateCheck([this] { scrollDateCheck(); }) , _scrollDateCheck([this] { scrollDateCheck(); })
, _applyUpdatedScrollState([this] { applyUpdatedScrollState(); }) , _applyUpdatedScrollState([this] { applyUpdatedScrollState(); })
, _selectEnabled(_delegate->listAllowsMultiSelect()) { , _selectEnabled(_delegate->listAllowsMultiSelect())
, _highlightTimer([this] { updateHighlightedMessage(); }) {
setMouseTracking(true); setMouseTracking(true);
_scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); }); _scrollDateHideTimer.setCallback([this] { scrollDateHideByTimer(); });
Auth().data().viewRepaintRequest( Auth().data().viewRepaintRequest(
@ -417,6 +418,32 @@ bool ListWidget::isBelowPosition(Data::MessagePosition position) const {
return _items.front()->data()->position() > position; return _items.front()->data()->position() > position;
} }
void ListWidget::highlightMessage(FullMsgId itemId) {
if (const auto item = App::histItemById(itemId)) {
if (const auto view = viewForItem(item)) {
_highlightStart = getms();
_highlightedMessageId = itemId;
_highlightTimer.callEach(AnimationTimerDelta);
repaintItem(view);
}
}
}
void ListWidget::updateHighlightedMessage() {
if (const auto item = App::histItemById(_highlightedMessageId)) {
if (const auto view = viewForItem(item)) {
repaintItem(view);
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
if (getms() - _highlightStart <= duration) {
return;
}
}
}
_highlightTimer.cancel();
_highlightedMessageId = FullMsgId();
}
void ListWidget::checkUnreadBarCreation() { void ListWidget::checkUnreadBarCreation() {
if (!_unreadBarElement) { if (!_unreadBarElement) {
if (const auto index = _delegate->listUnreadBarView(_items)) { if (const auto index = _delegate->listUnreadBarView(_items)) {
@ -1071,6 +1098,16 @@ void ListWidget::elementAnimationAutoplayAsync(
}); });
} }
TimeMs ListWidget::elementHighlightTime(
not_null<const HistoryView::Element*> element) {
if (element->data()->fullId() == _highlightedMessageId) {
if (_highlightTimer.isActive()) {
return getms() - _highlightStart;
}
}
return TimeMs(0);
}
void ListWidget::saveState(not_null<ListMemento*> memento) { void ListWidget::saveState(not_null<ListMemento*> memento) {
memento->setAroundPosition(_aroundPosition); memento->setAroundPosition(_aroundPosition);
auto state = countScrollState(); auto state = countScrollState();

View File

@ -149,6 +149,7 @@ public:
AnimatedScroll type); AnimatedScroll type);
bool isAbovePosition(Data::MessagePosition position) const; bool isAbovePosition(Data::MessagePosition position) const;
bool isBelowPosition(Data::MessagePosition position) const; bool isBelowPosition(Data::MessagePosition position) const;
void highlightMessage(FullMsgId itemId);
TextWithEntities getSelectedText() const; TextWithEntities getSelectedText() const;
MessageIdsList getSelectedItems() const; MessageIdsList getSelectedItems() const;
@ -175,6 +176,7 @@ public:
bool elementUnderCursor(not_null<const Element*> view) override; bool elementUnderCursor(not_null<const Element*> view) override;
void elementAnimationAutoplayAsync( void elementAnimationAutoplayAsync(
not_null<const Element*> view) override; not_null<const Element*> view) override;
TimeMs elementHighlightTime(not_null<const Element*> element) override;
~ListWidget(); ~ListWidget();
@ -378,6 +380,8 @@ private:
void applyUpdatedScrollState(); void applyUpdatedScrollState();
void scrollToAnimationCallback(FullMsgId attachToId); void scrollToAnimationCallback(FullMsgId attachToId);
void updateHighlightedMessage();
// This function finds all history items that are displayed and calls template method // 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. // for each found message (in given direction) in the passed history with passed top offset.
// //
@ -469,6 +473,10 @@ private:
QPoint _trippleClickPoint; QPoint _trippleClickPoint;
TimeMs _trippleClickStartTime = 0; TimeMs _trippleClickStartTime = 0;
TimeMs _highlightStart = 0;
FullMsgId _highlightedMessageId;
base::Timer _highlightTimer;
rpl::lifetime _viewerLifetime; rpl::lifetime _viewerLifetime;
}; };

View File

@ -342,6 +342,26 @@ QSize Message::performCountOptimalSize() {
return QSize(maxWidth, minHeight); return QSize(maxWidth, minHeight);
} }
int Message::marginTop() const {
auto result = 0;
if (!isHidden()) {
if (isAttachedToPrevious()) {
result += st::msgMarginTopAttached;
} else {
result += st::msgMargin.top();
}
}
result += displayedDateHeight();
if (const auto bar = Get<UnreadBar>()) {
result += bar->height();
}
return result;
}
int Message::marginBottom() const {
return isHidden() ? 0 : st::msgMargin.bottom();
}
void Message::draw( void Message::draw(
Painter &p, Painter &p,
QRect clip, QRect clip,
@ -376,25 +396,11 @@ void Message::draw(
return; return;
} }
auto fullAnimMs = App::main() ? App::main()->highlightStartTime(item) : 0LL; paintHighlight(p, g.height());
if (fullAnimMs > 0 && fullAnimMs <= ms) {
auto animms = ms - fullAnimMs;
if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
auto top = marginTop();
auto bottom = marginBottom();
auto fill = qMin(top, bottom);
auto skiptop = top - fill;
auto fillheight = fill + g.height() + fill;
auto dt = (animms > st::activeFadeInDuration) ? (1. - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration)); p.setTextPalette(selected
auto o = p.opacity(); ? (outbg ? st::outTextPaletteSelected : st::inTextPaletteSelected)
p.setOpacity(o * dt); : (outbg ? st::outTextPalette : st::inTextPalette));
p.fillRect(0, skiptop, width(), fillheight, st::defaultTextPalette.selectOverlay);
p.setOpacity(o);
}
}
p.setTextPalette(selected ? (outbg ? st::outTextPaletteSelected : st::inTextPaletteSelected) : (outbg ? st::outTextPalette : st::inTextPalette));
auto keyboard = item->inlineReplyKeyboard(); auto keyboard = item->inlineReplyKeyboard();
if (keyboard) { if (keyboard) {

View File

@ -32,6 +32,8 @@ public:
not_null<ElementDelegate*> delegate, not_null<ElementDelegate*> delegate,
not_null<HistoryMessage*> data); not_null<HistoryMessage*> data);
int marginTop() const override;
int marginBottom() const override;
void draw( void draw(
Painter &p, Painter &p,
QRect clip, QRect clip,

View File

@ -373,6 +373,14 @@ bool Service::isHidden() const {
return Element::isHidden(); return Element::isHidden();
} }
int Service::marginTop() const {
return st::msgServiceMargin.top();
}
int Service::marginBottom() const {
return st::msgServiceMargin.bottom();
}
void Service::draw( void Service::draw(
Painter &p, Painter &p,
QRect clip, QRect clip,
@ -410,23 +418,7 @@ void Service::draw(
return; return;
} }
auto fullAnimMs = App::main() ? App::main()->highlightStartTime(item) : 0LL; paintHighlight(p, height);
if (fullAnimMs > 0 && fullAnimMs <= ms) {
auto animms = ms - fullAnimMs;
if (animms < st::activeFadeInDuration + st::activeFadeOutDuration) {
auto top = st::msgServiceMargin.top();
auto bottom = st::msgServiceMargin.bottom();
auto fill = qMin(top, bottom);
auto skiptop = top - fill;
auto fillheight = fill + height + fill;
auto dt = (animms > st::activeFadeInDuration) ? (1. - (animms - st::activeFadeInDuration) / float64(st::activeFadeOutDuration)) : (animms / float64(st::activeFadeInDuration));
auto o = p.opacity();
p.setOpacity(o * dt);
p.fillRect(0, skiptop, width(), fillheight, st::defaultTextPalette.selectOverlay);
p.setOpacity(o);
}
}
p.setTextPalette(st::serviceTextPalette); p.setTextPalette(st::serviceTextPalette);

View File

@ -19,6 +19,8 @@ public:
not_null<ElementDelegate*> delegate, not_null<ElementDelegate*> delegate,
not_null<HistoryService*> data); not_null<HistoryService*> data);
int marginTop() const override;
int marginBottom() const override;
bool isHidden() const override; bool isHidden() const override;
void draw( void draw(
Painter &p, Painter &p,