mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 07:37:11 +02:00
Highlight album part that had a reply clicked.
This commit is contained in:
parent
39f9147790
commit
3a34881488
19 changed files with 154 additions and 63 deletions
|
@ -556,7 +556,7 @@ bool InnerWidget::elementUnderCursor(
|
|||
}
|
||||
|
||||
crl::time InnerWidget::elementHighlightTime(
|
||||
not_null<const HistoryView::Element*> element) {
|
||||
not_null<const HistoryItem*> item) {
|
||||
return crl::time(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
bool elementUnderCursor(
|
||||
not_null<const HistoryView::Element*> view) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const HistoryView::Element*> element) override;
|
||||
not_null<const HistoryItem*> item) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const HistoryView::Element*> view,
|
||||
|
|
|
@ -2520,9 +2520,9 @@ void HistoryInner::elementStartStickerLoop(
|
|||
_animatedStickersPlayed.emplace(view->data());
|
||||
}
|
||||
|
||||
crl::time HistoryInner::elementHighlightTime(not_null<const Element*> view) {
|
||||
const auto fullAnimMs = _controller->content()->highlightStartTime(
|
||||
view->data());
|
||||
crl::time HistoryInner::elementHighlightTime(
|
||||
not_null<const HistoryItem*> item) {
|
||||
const auto fullAnimMs = _controller->content()->highlightStartTime(item);
|
||||
if (fullAnimMs > 0) {
|
||||
const auto now = crl::now();
|
||||
if (fullAnimMs < now) {
|
||||
|
@ -3421,8 +3421,8 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
|
|||
return (App::hoveredItem() == view);
|
||||
}
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> view) override {
|
||||
return Instance ? Instance->elementHighlightTime(view) : 0;
|
||||
not_null<const HistoryItem*> item) override {
|
||||
return Instance ? Instance->elementHighlightTime(item) : 0;
|
||||
}
|
||||
bool elementInSelectionMode() override {
|
||||
return Instance ? Instance->inSelectionMode() : false;
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
int till) const;
|
||||
void elementStartStickerLoop(not_null<const Element*> view);
|
||||
[[nodiscard]] crl::time elementHighlightTime(
|
||||
not_null<const Element*> view);
|
||||
not_null<const HistoryItem*> item);
|
||||
void elementShowPollResults(
|
||||
not_null<PollData*> poll,
|
||||
FullMsgId context);
|
||||
|
|
|
@ -1045,11 +1045,6 @@ void HistoryWidget::scrollToAnimationCallback(
|
|||
|
||||
void HistoryWidget::enqueueMessageHighlight(
|
||||
not_null<HistoryView::Element*> view) {
|
||||
if (const auto group = session().data().groups().find(view->data())) {
|
||||
if (const auto leader = group->items.front()->mainView()) {
|
||||
view = leader;
|
||||
}
|
||||
}
|
||||
auto enqueueMessageId = [this](MsgId universalId) {
|
||||
if (_highlightQueue.empty() && !_highlightTimer.isActive()) {
|
||||
highlightMessage(universalId);
|
||||
|
@ -1096,7 +1091,7 @@ void HistoryWidget::checkNextHighlight() {
|
|||
|
||||
void HistoryWidget::updateHighlightedMessage() {
|
||||
const auto item = getItemFromHistoryOrMigrated(_highlightedMessageId);
|
||||
const auto view = item ? item->mainView() : nullptr;
|
||||
auto view = item ? item->mainView() : nullptr;
|
||||
if (!view) {
|
||||
return stopMessageHighlight();
|
||||
}
|
||||
|
@ -1105,6 +1100,11 @@ void HistoryWidget::updateHighlightedMessage() {
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ bool SimpleElementDelegate::elementUnderCursor(
|
|||
}
|
||||
|
||||
crl::time SimpleElementDelegate::elementHighlightTime(
|
||||
not_null<const Element*> element) {
|
||||
not_null<const HistoryItem*> item) {
|
||||
return crl::time(0);
|
||||
}
|
||||
|
||||
|
@ -280,29 +280,44 @@ void Element::refreshDataIdHook() {
|
|||
void Element::paintHighlight(
|
||||
Painter &p,
|
||||
int geometryHeight) const {
|
||||
const auto animms = delegate()->elementHighlightTime(this);
|
||||
if (!animms
|
||||
|| animms >= st::activeFadeInDuration + st::activeFadeOutDuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto top = marginTop();
|
||||
const auto bottom = marginBottom();
|
||||
const auto fill = qMin(top, bottom);
|
||||
const auto skiptop = top - fill;
|
||||
const auto fillheight = fill + geometryHeight + fill;
|
||||
|
||||
const auto dt = (animms > st::activeFadeInDuration)
|
||||
paintCustomHighlight(p, skiptop, fillheight, data());
|
||||
}
|
||||
|
||||
float64 Element::highlightOpacity(not_null<const HistoryItem*> item) const {
|
||||
const auto animms = delegate()->elementHighlightTime(item);
|
||||
if (!animms
|
||||
|| animms >= st::activeFadeInDuration + st::activeFadeOutDuration) {
|
||||
return 0.;
|
||||
}
|
||||
|
||||
return (animms > st::activeFadeInDuration)
|
||||
? (1. - (animms - st::activeFadeInDuration)
|
||||
/ float64(st::activeFadeOutDuration))
|
||||
: (animms / float64(st::activeFadeInDuration));
|
||||
}
|
||||
|
||||
void Element::paintCustomHighlight(
|
||||
Painter &p,
|
||||
int y,
|
||||
int height,
|
||||
not_null<const HistoryItem*> item) const {
|
||||
const auto opacity = highlightOpacity(item);
|
||||
if (opacity == 0.) {
|
||||
return;
|
||||
}
|
||||
const auto o = p.opacity();
|
||||
p.setOpacity(o * dt);
|
||||
p.setOpacity(o * opacity);
|
||||
p.fillRect(
|
||||
0,
|
||||
skiptop,
|
||||
y,
|
||||
width(),
|
||||
fillheight,
|
||||
height,
|
||||
st::defaultTextPalette.selectOverlay);
|
||||
p.setOpacity(o);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
Element *replacing = nullptr) = 0;
|
||||
virtual bool elementUnderCursor(not_null<const Element*> view) = 0;
|
||||
virtual crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) = 0;
|
||||
not_null<const HistoryItem*> item) = 0;
|
||||
virtual bool elementInSelectionMode() = 0;
|
||||
virtual bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
|
@ -87,7 +87,7 @@ public:
|
|||
Element *replacing = nullptr) override;
|
||||
bool elementUnderCursor(not_null<const Element*> view) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) override;
|
||||
not_null<const HistoryItem*> item) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
|
@ -301,6 +301,13 @@ public:
|
|||
virtual void unloadHeavyPart();
|
||||
void checkHeavyPart();
|
||||
|
||||
void paintCustomHighlight(
|
||||
Painter &p,
|
||||
int y,
|
||||
int height,
|
||||
not_null<const HistoryItem*> item) const;
|
||||
float64 highlightOpacity(not_null<const HistoryItem*> item) const;
|
||||
|
||||
// Legacy blocks structure.
|
||||
HistoryBlock *block();
|
||||
const HistoryBlock *block() const;
|
||||
|
|
|
@ -482,7 +482,7 @@ void ListWidget::highlightMessage(FullMsgId itemId) {
|
|||
_highlightedMessageId = itemId;
|
||||
_highlightTimer.callEach(AnimationTimerDelta);
|
||||
|
||||
repaintItem(view);
|
||||
repaintHighlightedItem(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -496,10 +496,24 @@ 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)) {
|
||||
repaintItem(view);
|
||||
repaintHighlightedItem(view);
|
||||
auto duration = st::activeFadeInDuration + st::activeFadeOutDuration;
|
||||
if (crl::now() - _highlightStart <= duration) {
|
||||
return;
|
||||
|
@ -1244,8 +1258,8 @@ bool ListWidget::elementUnderCursor(
|
|||
}
|
||||
|
||||
crl::time ListWidget::elementHighlightTime(
|
||||
not_null<const HistoryView::Element*> element) {
|
||||
if (element->data()->fullId() == _highlightedMessageId) {
|
||||
not_null<const HistoryItem*> item) {
|
||||
if (item->fullId() == _highlightedMessageId) {
|
||||
if (_highlightTimer.isActive()) {
|
||||
return crl::now() - _highlightStart;
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ public:
|
|||
Element *replacing = nullptr) override;
|
||||
bool elementUnderCursor(not_null<const Element*> view) override;
|
||||
crl::time elementHighlightTime(
|
||||
not_null<const Element*> element) override;
|
||||
not_null<const HistoryItem*> item) override;
|
||||
bool elementInSelectionMode() override;
|
||||
bool elementIntersectsRange(
|
||||
not_null<const Element*> view,
|
||||
|
@ -340,6 +340,7 @@ 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);
|
||||
|
|
|
@ -570,7 +570,40 @@ void Message::draw(
|
|||
return;
|
||||
}
|
||||
|
||||
paintHighlight(p, g.height());
|
||||
auto entry = logEntryOriginal();
|
||||
auto mediaDisplayed = media && media->isDisplayed();
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
auto mediaSelectionIntervals = (!selected && mediaDisplayed)
|
||||
? media->getBubbleSelectionIntervals(selection)
|
||||
: std::vector<BubbleSelectionInterval>();
|
||||
auto localMediaTop = 0;
|
||||
const auto customHighlight = mediaDisplayed && media->customHighlight();
|
||||
if (!mediaSelectionIntervals.empty() || customHighlight) {
|
||||
auto localMediaBottom = g.top() + g.height();
|
||||
if (data()->repliesAreComments() || data()->externalReply()) {
|
||||
localMediaBottom -= st::historyCommentsButtonHeight;
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
localMediaBottom -= st::msgPadding.bottom();
|
||||
}
|
||||
if (entry) {
|
||||
localMediaBottom -= entry->height();
|
||||
}
|
||||
localMediaTop = localMediaBottom - media->height();
|
||||
for (auto &[top, height] : mediaSelectionIntervals) {
|
||||
top += localMediaTop;
|
||||
}
|
||||
}
|
||||
|
||||
if (customHighlight) {
|
||||
media->drawHighlight(p, localMediaTop);
|
||||
} else {
|
||||
paintHighlight(p, g.height());
|
||||
}
|
||||
|
||||
const auto roll = media ? media->bubbleRoll() : Media::BubbleRoll();
|
||||
if (roll) {
|
||||
|
@ -602,34 +635,6 @@ void Message::draw(
|
|||
fromNameUpdated(g.width());
|
||||
}
|
||||
|
||||
auto entry = logEntryOriginal();
|
||||
auto mediaDisplayed = media && media->isDisplayed();
|
||||
|
||||
// Entry page is always a bubble bottom.
|
||||
auto mediaOnBottom = (mediaDisplayed && media->isBubbleBottom()) || (entry/* && entry->isBubbleBottom()*/);
|
||||
auto mediaOnTop = (mediaDisplayed && media->isBubbleTop()) || (entry && entry->isBubbleTop());
|
||||
|
||||
|
||||
auto mediaSelectionIntervals = (!selected && mediaDisplayed)
|
||||
? media->getBubbleSelectionIntervals(selection)
|
||||
: std::vector<BubbleSelectionInterval>();
|
||||
if (!mediaSelectionIntervals.empty()) {
|
||||
auto localMediaBottom = g.top() + g.height();
|
||||
if (data()->repliesAreComments() || data()->externalReply()) {
|
||||
localMediaBottom -= st::historyCommentsButtonHeight;
|
||||
}
|
||||
if (!mediaOnBottom) {
|
||||
localMediaBottom -= st::msgPadding.bottom();
|
||||
}
|
||||
if (entry) {
|
||||
localMediaBottom -= entry->height();
|
||||
}
|
||||
const auto localMediaTop = localMediaBottom - media->height();
|
||||
for (auto &[top, height] : mediaSelectionIntervals) {
|
||||
top += localMediaTop;
|
||||
}
|
||||
}
|
||||
|
||||
auto skipTail = isAttachedToNext()
|
||||
|| (media && media->skipBubbleTail())
|
||||
|| (keyboard != nullptr)
|
||||
|
|
|
@ -951,6 +951,7 @@ void Document::drawGrouped(
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
p.translate(geometry.topLeft());
|
||||
|
|
|
@ -72,6 +72,7 @@ public:
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const override;
|
||||
TextState getStateGrouped(
|
||||
|
|
|
@ -901,6 +901,7 @@ void Gif::drawGrouped(
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
ensureDataMediaCreated();
|
||||
|
@ -989,8 +990,16 @@ void Gif::drawGrouped(
|
|||
p.drawPixmap(geometry, *cache);
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
const auto overlayOpacity = selected
|
||||
? (1. - highlightOpacity)
|
||||
: highlightOpacity;
|
||||
if (overlayOpacity > 0.) {
|
||||
p.setOpacity(overlayOpacity);
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
if (!selected) {
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
if (radial
|
||||
|
|
|
@ -79,6 +79,7 @@ public:
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const override;
|
||||
TextState getStateGrouped(
|
||||
|
|
|
@ -84,6 +84,8 @@ public:
|
|||
}
|
||||
virtual void refreshParentId(not_null<HistoryItem*> realParent) {
|
||||
}
|
||||
virtual void drawHighlight(Painter &p, int top) const {
|
||||
}
|
||||
virtual void draw(
|
||||
Painter &p,
|
||||
const QRect &r,
|
||||
|
@ -177,6 +179,7 @@ public:
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
Unexpected("Grouping method call.");
|
||||
|
@ -274,6 +277,9 @@ public:
|
|||
const QRect &bubble,
|
||||
crl::time ms) const {
|
||||
}
|
||||
[[nodiscard]] virtual bool customHighlight() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool hasHeavyPart() const {
|
||||
return false;
|
||||
|
|
|
@ -268,6 +268,18 @@ QMargins GroupedMedia::groupedPadding() const {
|
|||
(normal.bottom() - grouped.bottom()) + addToBottom);
|
||||
}
|
||||
|
||||
void GroupedMedia::drawHighlight(Painter &p, int top) const {
|
||||
if (_mode != Mode::Column) {
|
||||
return;
|
||||
}
|
||||
const auto skip = top + groupedPadding().top();
|
||||
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
|
||||
const auto &part = _parts[i];
|
||||
const auto rect = part.geometry.translated(0, skip);
|
||||
_parent->paintCustomHighlight(p, rect.y(), rect.height(), part.item);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupedMedia::draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
|
@ -290,6 +302,9 @@ void GroupedMedia::draw(
|
|||
if (textSelection) {
|
||||
selection = part.content->skipSelection(selection);
|
||||
}
|
||||
const auto highlightOpacity = (_mode == Mode::Grid)
|
||||
? _parent->highlightOpacity(part.item)
|
||||
: 0.;
|
||||
part.content->drawGrouped(
|
||||
p,
|
||||
clip,
|
||||
|
@ -298,6 +313,7 @@ void GroupedMedia::draw(
|
|||
part.geometry.translated(0, groupPadding.top()),
|
||||
part.sides,
|
||||
cornersFromSides(part.sides),
|
||||
highlightOpacity,
|
||||
&part.cacheKey,
|
||||
&part.cache);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
|
||||
void refreshParentId(not_null<HistoryItem*> realParent) override;
|
||||
|
||||
void drawHighlight(Painter &p, int top) const override;
|
||||
void draw(
|
||||
Painter &p,
|
||||
const QRect &clip,
|
||||
|
@ -87,6 +88,9 @@ public:
|
|||
bool allowsFastShare() const override {
|
||||
return true;
|
||||
}
|
||||
bool customHighlight() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
void stopAnimation() override;
|
||||
void checkAnimation() override;
|
||||
|
|
|
@ -485,6 +485,7 @@ void Photo::drawGrouped(
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const {
|
||||
ensureDataMediaCreated();
|
||||
|
@ -509,9 +510,18 @@ void Photo::drawGrouped(
|
|||
// App::roundShadow(p, 0, 0, paintw, painth, selected ? st::msgInShadowSelected : st::msgInShadow, selected ? InSelectedShadowCorners : InShadowCorners);
|
||||
}
|
||||
p.drawPixmap(geometry.topLeft(), *cache);
|
||||
if (selected) {
|
||||
|
||||
const auto overlayOpacity = selected
|
||||
? (1. - highlightOpacity)
|
||||
: highlightOpacity;
|
||||
if (overlayOpacity > 0.) {
|
||||
p.setOpacity(overlayOpacity);
|
||||
const auto roundRadius = ImageRoundRadius::Large;
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
if (!selected) {
|
||||
Ui::FillComplexOverlayRect(p, geometry, roundRadius, corners);
|
||||
}
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
|
||||
const auto displayState = radial
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
const QRect &geometry,
|
||||
RectParts sides,
|
||||
RectParts corners,
|
||||
float64 highlightOpacity,
|
||||
not_null<uint64*> cacheKey,
|
||||
not_null<QPixmap*> cache) const override;
|
||||
TextState getStateGrouped(
|
||||
|
|
Loading…
Add table
Reference in a new issue