mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Show pinned messages.
This commit is contained in:
@@ -1719,6 +1719,7 @@ groupCallMessagePalette: TextPalette(defaultTextPalette) {
|
||||
monoFg: radialFg;
|
||||
spoilerFg: radialFg;
|
||||
}
|
||||
groupCallPinnedMaxWidth: 96px;
|
||||
groupCallUserpic: 20px;
|
||||
groupCallUserpicPadding: margins(2px, 2px, 4px, 2px);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace Calls::Group {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMessageBgOpacity = 0.8;
|
||||
constexpr auto kColoredMessageBgOpacity = 0.7;
|
||||
constexpr auto kColoredMessageBgOpacity = 0.8;
|
||||
|
||||
[[nodiscard]] int CountMessageRadius() {
|
||||
const auto minHeight = st::groupCallMessagePadding.top()
|
||||
@@ -149,7 +149,7 @@ void ReceiveSomeMouseEvents(
|
||||
struct MessagesUi::MessageView {
|
||||
MsgId id = 0;
|
||||
MsgId sendingId = 0;
|
||||
PeerData *from = nullptr;
|
||||
not_null<PeerData*> from;
|
||||
ClickHandlerPtr fromLink;
|
||||
Ui::Animations::Simple toggleAnimation;
|
||||
Ui::Animations::Simple sentAnimation;
|
||||
@@ -172,6 +172,21 @@ struct MessagesUi::MessageView {
|
||||
bool failed = false;
|
||||
};
|
||||
|
||||
struct MessagesUi::PinnedView {
|
||||
MsgId id = 0;
|
||||
not_null<PeerData*> from;
|
||||
Ui::Animations::Simple toggleAnimation;
|
||||
Ui::PeerUserpicView view;
|
||||
Ui::Text::String text;
|
||||
int stars = 0;
|
||||
int top = 0;
|
||||
int width = 0;
|
||||
int left = 0;
|
||||
int height = 0;
|
||||
int realWidth = 0;
|
||||
bool removed = false;
|
||||
};
|
||||
|
||||
MessagesUi::PayedBg::PayedBg(const Ui::StarsColoring &coloring)
|
||||
: color(Ui::ColorFromSerialized(coloring.bg2))
|
||||
, rounded(CountMessageRadius(), color.color()) {
|
||||
@@ -193,7 +208,8 @@ MessagesUi::MessagesUi(
|
||||
return result;
|
||||
})
|
||||
, _messageBgRect(CountMessageRadius(), _messageBg.color())
|
||||
, _fadeHeight(st::normalFont->height)
|
||||
, _fadeHeight(st::normalFont->height * 2)
|
||||
, _fadeWidth(st::normalFont->height * 2)
|
||||
, _streamMode(_mode == MessagesMode::VideoStream) {
|
||||
setupList(std::move(messages), std::move(shown));
|
||||
handleIdUpdates(std::move(idUpdates));
|
||||
@@ -214,26 +230,35 @@ void MessagesUi::setupList(
|
||||
auto from = begin(list);
|
||||
auto till = end(list);
|
||||
for (auto &entry : _views) {
|
||||
if (!entry.removed) {
|
||||
const auto id = entry.id;
|
||||
const auto i = ranges::find(
|
||||
from,
|
||||
till,
|
||||
id,
|
||||
&Message::id);
|
||||
if (i == till) {
|
||||
toggleMessage(entry, false);
|
||||
continue;
|
||||
} else if (entry.failed != i->failed) {
|
||||
setContentFailed(entry);
|
||||
updateMessageSize(entry);
|
||||
repaintMessage(entry.id);
|
||||
} else if (entry.sending != (i->date == 0)) {
|
||||
animateMessageSent(entry);
|
||||
}
|
||||
if (i == from) {
|
||||
++from;
|
||||
if (entry.removed) {
|
||||
continue;
|
||||
}
|
||||
const auto id = entry.id;
|
||||
const auto i = ranges::find(
|
||||
from,
|
||||
till,
|
||||
id,
|
||||
&Message::id);
|
||||
if (i == till) {
|
||||
toggleMessage(entry, false);
|
||||
continue;
|
||||
} else if (entry.failed != i->failed) {
|
||||
setContentFailed(entry);
|
||||
updateMessageSize(entry);
|
||||
repaintMessage(entry.id);
|
||||
} else if (entry.sending != (i->date == 0)) {
|
||||
animateMessageSent(entry);
|
||||
}
|
||||
if (i == from) {
|
||||
if (i->stars
|
||||
&& i->date
|
||||
&& !ranges::contains(
|
||||
_pinnedViews,
|
||||
i->id,
|
||||
&PinnedView::id)) {
|
||||
appendPinned(*i);
|
||||
}
|
||||
++from;
|
||||
}
|
||||
}
|
||||
auto addedSendingToBottom = false;
|
||||
@@ -243,14 +268,21 @@ void MessagesUi::setupList(
|
||||
addedSendingToBottom = true;
|
||||
}
|
||||
appendMessage(*i);
|
||||
if (i->stars && i->date) {
|
||||
appendPinned(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addedSendingToBottom) {
|
||||
const auto from = _scroll->scrollTop();
|
||||
const auto till = _scroll->scrollTopMax();
|
||||
if (from >= till) {
|
||||
return;
|
||||
}
|
||||
_scrollToBottomAnimation.start([=] {
|
||||
_scroll->scrollToY(_scrollToBottomAnimation.value(till));
|
||||
}, from, till, st::slideDuration, anim::easeOutCirc);
|
||||
_scroll->scrollToY(_scroll->scrollTopMax()
|
||||
- _scrollToBottomAnimation.value(0));
|
||||
}, till - from, 0, st::slideDuration, anim::easeOutCirc);
|
||||
}
|
||||
}, _lifetime);
|
||||
}
|
||||
@@ -328,6 +360,45 @@ bool MessagesUi::updateMessageHeight(MessageView &entry) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void MessagesUi::updatePinnedSize(PinnedView &entry) {
|
||||
const auto &padding = st::groupCallMessagePadding;
|
||||
|
||||
const auto userpicPadding = st::groupCallUserpicPadding;
|
||||
const auto userpicSize = st::groupCallUserpic;
|
||||
const auto leftSkip = userpicPadding.left()
|
||||
+ userpicSize
|
||||
+ userpicPadding.right();
|
||||
const auto inner = std::min(
|
||||
entry.text.maxWidth(),
|
||||
st::groupCallPinnedMaxWidth);
|
||||
|
||||
const auto textHeight = st::messageTextStyle.font->height;
|
||||
const auto userpicHeight = userpicPadding.top()
|
||||
+ userpicSize
|
||||
+ userpicPadding.bottom();
|
||||
entry.height = std::max(
|
||||
padding.top() + textHeight + padding.bottom(),
|
||||
userpicHeight);
|
||||
entry.top = 0;
|
||||
|
||||
const auto skip = st::groupCallMessageSkip;
|
||||
entry.realWidth = skip + leftSkip + inner + padding.right();
|
||||
}
|
||||
|
||||
bool MessagesUi::updatePinnedWidth(PinnedView &entry) {
|
||||
const auto width = entry.toggleAnimation.animating()
|
||||
? anim::interpolate(
|
||||
0,
|
||||
entry.realWidth,
|
||||
entry.toggleAnimation.value(entry.removed ? 0. : 1.))
|
||||
: entry.realWidth;
|
||||
if (entry.width == width) {
|
||||
return false;
|
||||
}
|
||||
entry.width = width;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MessagesUi::setContentFailed(MessageView &entry) {
|
||||
entry.failed = true;
|
||||
entry.text = Ui::Text::String(
|
||||
@@ -454,18 +525,22 @@ void MessagesUi::appendMessage(const Message &data) {
|
||||
setupMessagesWidget();
|
||||
}
|
||||
|
||||
auto &entry = _views.emplace_back();
|
||||
const auto id = entry.id = data.id;
|
||||
entry.stars = data.stars;
|
||||
const auto id = data.id;
|
||||
const auto peer = data.peer;
|
||||
auto &entry = _views.emplace_back(MessageView{
|
||||
.id = id,
|
||||
.from = peer,
|
||||
.stars = data.stars,
|
||||
.top = top,
|
||||
.sending = !data.date,
|
||||
});
|
||||
const auto repaint = [=] {
|
||||
repaintMessage(id);
|
||||
};
|
||||
const auto peer = entry.from = data.peer;
|
||||
entry.fromLink = std::make_shared<LambdaClickHandler>([=] {
|
||||
_show->show(
|
||||
PrepareShortInfoBox(peer, _show, &st::storiesShortInfoBox));
|
||||
});
|
||||
entry.sending = !data.date;
|
||||
if (data.failed) {
|
||||
setContentFailed(entry);
|
||||
} else {
|
||||
@@ -473,7 +548,6 @@ void MessagesUi::appendMessage(const Message &data) {
|
||||
.append(' ').append(data.text);
|
||||
setContent(entry, text, data.stars);
|
||||
}
|
||||
entry.top = top;
|
||||
updateMessageSize(entry);
|
||||
if (entry.sending) {
|
||||
using namespace Ui;
|
||||
@@ -488,6 +562,93 @@ void MessagesUi::appendMessage(const Message &data) {
|
||||
checkReactionContent(entry, data.text);
|
||||
}
|
||||
|
||||
void MessagesUi::togglePinned(PinnedView &entry, bool shown) {
|
||||
const auto id = entry.id;
|
||||
entry.removed = !shown;
|
||||
entry.toggleAnimation.start(
|
||||
[=] { repaintPinned(id); },
|
||||
shown ? 0. : 1.,
|
||||
shown ? 1. : 0.,
|
||||
st::slideWrapDuration,
|
||||
shown ? anim::easeOutCirc : anim::easeInCirc);
|
||||
repaintPinned(id);
|
||||
}
|
||||
|
||||
void MessagesUi::repaintPinned(MsgId id) {
|
||||
auto i = ranges::find(_pinnedViews, id, &PinnedView::id);
|
||||
if (i == end(_pinnedViews)) {
|
||||
return;
|
||||
} else if (i->removed && !i->toggleAnimation.animating()) {
|
||||
const auto left = i->left;
|
||||
i = _pinnedViews.erase(i);
|
||||
recountWidths(i, left);
|
||||
return;
|
||||
}
|
||||
if (i->toggleAnimation.animating() || i->width != i->realWidth) {
|
||||
const auto was = i->width;
|
||||
if (updatePinnedWidth(*i)) {
|
||||
if (i->width > was) {
|
||||
const auto larger = countPinnedScrollSkip(*i);
|
||||
if (larger > _pinnedScrollSkip) {
|
||||
setPinnedScrollSkip(larger);
|
||||
}
|
||||
} else {
|
||||
applyGeometryToPinned();
|
||||
}
|
||||
recountWidths(i, i->left);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_pinned->update(i->left, 0, i->width, _pinned->height());
|
||||
}
|
||||
|
||||
void MessagesUi::recountWidths(
|
||||
std::vector<PinnedView>::iterator i,
|
||||
int left) {
|
||||
auto from = left;
|
||||
for (auto e = end(_pinnedViews); i != e; ++i) {
|
||||
i->left = left;
|
||||
left += i->width;
|
||||
}
|
||||
if (_pinnedViews.empty()) {
|
||||
delete base::take(_pinned);
|
||||
_pinnedScroll = nullptr;
|
||||
} else {
|
||||
updateGeometries();
|
||||
_pinned->update(from, 0, left - from, _pinned->height());
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesUi::appendPinned(const Message &data) {
|
||||
if (!_pinnedScroll) {
|
||||
setupPinnedWidget();
|
||||
}
|
||||
|
||||
const auto id = data.id;
|
||||
const auto peer = data.peer;
|
||||
const auto i = ranges::lower_bound(
|
||||
_pinnedViews,
|
||||
data.stars,
|
||||
ranges::greater(),
|
||||
&PinnedView::stars);
|
||||
const auto left = (i == end(_pinnedViews)) ? 0 : i->left;
|
||||
auto &entry = *_pinnedViews.insert(i, PinnedView{
|
||||
.id = data.id,
|
||||
.from = peer,
|
||||
.stars = data.stars,
|
||||
.left = left,
|
||||
});
|
||||
const auto repaint = [=] {
|
||||
repaintPinned(id);
|
||||
};
|
||||
entry.text.setMarkedText(
|
||||
st::messageTextStyle,
|
||||
Ui::Text::Bold(data.peer->shortName()));
|
||||
updatePinnedSize(entry);
|
||||
entry.width = 0;
|
||||
togglePinned(entry, true);
|
||||
}
|
||||
|
||||
void MessagesUi::checkReactionContent(
|
||||
MessageView &entry,
|
||||
const TextWithEntities &text) {
|
||||
@@ -643,6 +804,41 @@ void MessagesUi::updateBottomFade() {
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesUi::updateLeftFade() {
|
||||
const auto leftFadeShown = (_pinnedScroll->scrollLeft() > 0);
|
||||
if (_leftFadeShown != leftFadeShown) {
|
||||
_leftFadeShown = leftFadeShown;
|
||||
//const auto from = leftFadeShown ? 0. : 1.;
|
||||
//const auto till = rightFadeShown ? 1. : 0.;
|
||||
//_leftFadeAnimation.start([=] {
|
||||
_pinned->update(
|
||||
_pinnedScroll->scrollLeft(),
|
||||
0,
|
||||
_fadeWidth,
|
||||
_pinned->height());
|
||||
//}, from, till, st::slideWrapDuration);
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesUi::updateRightFade() {
|
||||
const auto max = _pinnedScroll->scrollLeftMax();
|
||||
const auto rightFadeShown = (_pinnedScroll->scrollLeft() < max);
|
||||
if (_rightFadeShown != rightFadeShown) {
|
||||
_rightFadeShown = rightFadeShown;
|
||||
//const auto from = rightFadeShown ? 0. : 1.;
|
||||
//const auto till = rightFadeShown ? 1. : 0.;
|
||||
//_rightFadeAnimation.start([=] {
|
||||
_pinned->update(
|
||||
(_pinnedScroll->scrollLeft()
|
||||
+ _pinnedScroll->width()
|
||||
- _fadeWidth),
|
||||
0,
|
||||
_fadeWidth,
|
||||
_pinned->height());
|
||||
//}, from, till, st::slideWrapDuration);
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesUi::setupMessagesWidget() {
|
||||
_scroll = std::make_unique<Ui::ElasticScroll>(
|
||||
_parent,
|
||||
@@ -650,6 +846,7 @@ void MessagesUi::setupMessagesWidget() {
|
||||
const auto scroll = _scroll.get();
|
||||
|
||||
_messages = scroll->setOwnedWidget(object_ptr<Ui::RpWidget>(scroll));
|
||||
_messages->move(0, 0);
|
||||
rpl::combine(
|
||||
scroll->scrollTopValue(),
|
||||
scroll->heightValue(),
|
||||
@@ -726,7 +923,6 @@ void MessagesUi::setupMessagesWidget() {
|
||||
const auto y = entry.top;
|
||||
const auto use = entry.realHeight - skip;
|
||||
const auto width = entry.width;
|
||||
p.setBrush(st::radialBg);
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto scaled = (entry.height < entry.realHeight);
|
||||
if (scaled) {
|
||||
@@ -769,7 +965,7 @@ void MessagesUi::setupMessagesWidget() {
|
||||
.position = position,
|
||||
.size = userpicSize,
|
||||
.shape = Ui::PeerUserpicShape::Circle,
|
||||
});
|
||||
});
|
||||
if (const auto animation = entry.sendingAnimation.get()) {
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
auto pen = st::groupCallBg->p;
|
||||
@@ -793,7 +989,7 @@ void MessagesUi::setupMessagesWidget() {
|
||||
+ userpicPadding.right();
|
||||
}
|
||||
|
||||
p.setPen(st::radialFg);
|
||||
p.setPen(st::white);
|
||||
entry.text.draw(p, {
|
||||
.position = {
|
||||
x + leftSkip,
|
||||
@@ -818,14 +1014,16 @@ void MessagesUi::setupMessagesWidget() {
|
||||
startReactionAnimation(entry);
|
||||
}
|
||||
|
||||
p.restore();
|
||||
if (scaled) {
|
||||
p.restore();
|
||||
}
|
||||
}
|
||||
p.translate(0, start);
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
const auto topFade = _topFadeAnimation.value(
|
||||
const auto topFade = (//_topFadeAnimation.value(
|
||||
_topFadeShown ? 1. : 0.);
|
||||
if (topFade) {
|
||||
auto gradientTop = QLinearGradient(0, 0, 0, _fadeHeight);
|
||||
@@ -838,7 +1036,7 @@ void MessagesUi::setupMessagesWidget() {
|
||||
p.drawRect(0, 0, scroll->width(), _fadeHeight);
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
const auto bottomFade = _bottomFadeAnimation.value(
|
||||
const auto bottomFade = (//_bottomFadeAnimation.value(
|
||||
_bottomFadeShown ? 1. : 0.);
|
||||
if (bottomFade) {
|
||||
const auto till = scroll->height();
|
||||
@@ -858,39 +1056,241 @@ void MessagesUi::setupMessagesWidget() {
|
||||
}, _lifetime);
|
||||
|
||||
scroll->show();
|
||||
applyWidth();
|
||||
applyGeometry();
|
||||
}
|
||||
|
||||
void MessagesUi::applyWidth() {
|
||||
if (!_scroll) {
|
||||
return;
|
||||
}
|
||||
auto top = 0;
|
||||
for (auto &entry : _views) {
|
||||
entry.top = top;
|
||||
void MessagesUi::setupPinnedWidget() {
|
||||
_pinnedScroll = std::make_unique<Ui::ElasticScroll>(
|
||||
_parent,
|
||||
st::groupCallMessagesScroll,
|
||||
Qt::Horizontal);
|
||||
const auto scroll = _pinnedScroll.get();
|
||||
|
||||
updateMessageSize(entry);
|
||||
updateMessageHeight(entry);
|
||||
_pinned = scroll->setOwnedWidget(object_ptr<Ui::RpWidget>(scroll));
|
||||
_pinned->move(0, 0);
|
||||
rpl::combine(
|
||||
scroll->scrollLeftValue(),
|
||||
scroll->widthValue(),
|
||||
_pinned->widthValue()
|
||||
) | rpl::start_with_next([=] {
|
||||
updateLeftFade();
|
||||
updateRightFade();
|
||||
}, scroll->lifetime());
|
||||
|
||||
top += entry.height;
|
||||
_pinned->paintRequest() | rpl::start_with_next([=](QRect clip) {
|
||||
const auto start = scroll->scrollLeft();
|
||||
const auto end = start + scroll->width();
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
|
||||
if ((_pinnedCanvas.width() < scroll->width() * ratio)
|
||||
|| (_pinnedCanvas.height() < scroll->height() * ratio)) {
|
||||
_pinnedCanvas = QImage(
|
||||
scroll->size() * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_pinnedCanvas.setDevicePixelRatio(ratio);
|
||||
}
|
||||
auto p = Painter(&_pinnedCanvas);
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_Clear);
|
||||
p.fillRect(QRect(QPoint(), scroll->size()), QColor(0, 0, 0, 0));
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
const auto now = crl::now();
|
||||
const auto skip = st::groupCallMessageSkip;
|
||||
const auto padding = st::groupCallMessagePadding;
|
||||
p.translate(-start, 0);
|
||||
for (auto &entry : _pinnedViews) {
|
||||
if (entry.width <= skip || entry.left + entry.width <= start) {
|
||||
continue;
|
||||
} else if (entry.left >= end) {
|
||||
break;
|
||||
}
|
||||
const auto x = entry.left;
|
||||
const auto y = entry.top;
|
||||
const auto use = entry.realWidth - skip;
|
||||
const auto height = entry.height;
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto scaled = (entry.width < entry.realWidth);
|
||||
if (scaled) {
|
||||
const auto used = entry.width - skip;
|
||||
const auto mx = scaled ? (x + (used / 2)) : 0;
|
||||
const auto my = scaled ? (y + (height / 2)) : 0;
|
||||
const auto scale = used / float64(use);
|
||||
p.save();
|
||||
p.translate(mx, my);
|
||||
p.scale(scale, scale);
|
||||
p.setOpacity(scale);
|
||||
p.translate(-mx, -my);
|
||||
}
|
||||
const auto coloring = Ui::StarsColoringForCount(entry.stars);
|
||||
auto &bg = _bgs[ColoringKey(coloring)];
|
||||
if (!bg) {
|
||||
bg = std::make_unique<PayedBg>(coloring);
|
||||
}
|
||||
p.setOpacity(kColoredMessageBgOpacity);
|
||||
bg->rounded.paint(p, { x, y, use, height });
|
||||
p.setOpacity(1.);
|
||||
|
||||
const auto userpicSize = st::groupCallUserpic;
|
||||
const auto userpicPadding = st::groupCallUserpicPadding;
|
||||
const auto position = QPoint(
|
||||
x + userpicPadding.left(),
|
||||
y + userpicPadding.top());
|
||||
const auto rect = QRect(
|
||||
position,
|
||||
QSize(userpicSize, userpicSize));
|
||||
entry.from->paintUserpic(p, entry.view, {
|
||||
.position = position,
|
||||
.size = userpicSize,
|
||||
.shape = Ui::PeerUserpicShape::Circle,
|
||||
});
|
||||
const auto leftSkip = userpicPadding.left()
|
||||
+ userpicSize
|
||||
+ userpicPadding.right();
|
||||
|
||||
p.setPen(st::white);
|
||||
entry.text.draw(p, {
|
||||
.position = {
|
||||
x + leftSkip,
|
||||
y + padding.top(),
|
||||
},
|
||||
.availableWidth = entry.width - leftSkip - padding.right(),
|
||||
.palette = &st::groupCallMessagePalette,
|
||||
.spoiler = Ui::Text::DefaultSpoilerCache(),
|
||||
.now = now,
|
||||
.paused = !_messages->window()->isActiveWindow(),
|
||||
});
|
||||
if (scaled) {
|
||||
p.restore();
|
||||
}
|
||||
}
|
||||
p.translate(start, 0);
|
||||
|
||||
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
|
||||
p.setPen(Qt::NoPen);
|
||||
|
||||
const auto leftFade = (//_leftFadeAnimation.value(
|
||||
_leftFadeShown ? 1. : 0.);
|
||||
if (leftFade) {
|
||||
auto gradientLeft = QLinearGradient(0, 0, _fadeWidth, 0);
|
||||
gradientLeft.setStops({
|
||||
{ 0., QColor(255, 255, 255, 0) },
|
||||
{ 1., QColor(255, 255, 255, 255) },
|
||||
});
|
||||
p.setOpacity(leftFade);
|
||||
p.setBrush(gradientLeft);
|
||||
p.drawRect(0, 0, _fadeWidth, scroll->height());
|
||||
p.setOpacity(1.);
|
||||
}
|
||||
const auto rightFade = (//_rightFadeAnimation.value(
|
||||
_rightFadeShown ? 1. : 0.);
|
||||
if (rightFade) {
|
||||
const auto till = scroll->width();
|
||||
const auto from = till - _fadeWidth;
|
||||
auto gradientRight = QLinearGradient(from, 0, till, 0);
|
||||
gradientRight.setStops({
|
||||
{ 0., QColor(255, 255, 255, 255) },
|
||||
{ 1., QColor(255, 255, 255, 0) },
|
||||
});
|
||||
p.setBrush(gradientRight);
|
||||
p.drawRect(from, 0, _fadeWidth, scroll->height());
|
||||
}
|
||||
QPainter(_pinned).drawImage(
|
||||
QRect(QPoint(start, 0), scroll->size()),
|
||||
_pinnedCanvas,
|
||||
QRect(QPoint(), scroll->size() * ratio));
|
||||
}, _lifetime);
|
||||
|
||||
scroll->show();
|
||||
applyGeometry();
|
||||
}
|
||||
|
||||
void MessagesUi::applyGeometry() {
|
||||
if (_scroll) {
|
||||
auto top = 0;
|
||||
for (auto &entry : _views) {
|
||||
entry.top = top;
|
||||
|
||||
updateMessageSize(entry);
|
||||
updateMessageHeight(entry);
|
||||
|
||||
top += entry.height;
|
||||
}
|
||||
}
|
||||
applyGeometryToPinned();
|
||||
updateGeometries();
|
||||
}
|
||||
|
||||
void MessagesUi::applyGeometryToPinned() {
|
||||
if (!_pinnedScroll) {
|
||||
setPinnedScrollSkip(0);
|
||||
return;
|
||||
}
|
||||
const auto skip = st::groupCallMessageSkip;
|
||||
auto maxHeight = 0;
|
||||
auto left = 0;
|
||||
for (auto &entry : _pinnedViews) {
|
||||
entry.left = left;
|
||||
updatePinnedSize(entry);
|
||||
updatePinnedWidth(entry);
|
||||
left += entry.width;
|
||||
|
||||
if (maxHeight < entry.height + skip) {
|
||||
const auto possible = countPinnedScrollSkip(entry);
|
||||
maxHeight = std::max(possible, maxHeight);
|
||||
}
|
||||
}
|
||||
setPinnedScrollSkip(maxHeight);
|
||||
}
|
||||
|
||||
int MessagesUi::countPinnedScrollSkip(const PinnedView &entry) const {
|
||||
const auto skip = st::groupCallMessageSkip;
|
||||
if (!entry.toggleAnimation.animating()) {
|
||||
return entry.height + skip;
|
||||
}
|
||||
const auto used = ((entry.height + skip) * entry.width)
|
||||
/ float64(entry.realWidth);
|
||||
return int(base::SafeRound(used));
|
||||
}
|
||||
|
||||
void MessagesUi::setPinnedScrollSkip(int skip) {
|
||||
if (_pinnedScrollSkip != skip) {
|
||||
_pinnedScrollSkip = skip;
|
||||
updateGeometries();
|
||||
}
|
||||
}
|
||||
|
||||
void MessagesUi::updateGeometries() {
|
||||
const auto scrollBottom = (_scroll->scrollTop() + _scroll->height());
|
||||
const auto atBottom = (scrollBottom >= _messages->height());
|
||||
if (_pinnedScroll) {
|
||||
const auto skip = st::groupCallMessageSkip;
|
||||
const auto width = _pinnedViews.empty()
|
||||
? 0
|
||||
: (_pinnedViews.back().left + _pinnedViews.back().width - skip);
|
||||
const auto height = _pinnedViews.empty()
|
||||
? 0
|
||||
: _pinnedViews.back().height;
|
||||
const auto bottom = _bottom - st::groupCallMessageSkip;
|
||||
_pinned->resize(width, height);
|
||||
|
||||
const auto height = _views.empty()
|
||||
? 0
|
||||
: (_views.back().top + _views.back().height);
|
||||
_messages->setGeometry(0, 0, _width, height);
|
||||
const auto min = std::min(width, _width);
|
||||
_pinnedScroll->setGeometry(_left, bottom - height, min, height);
|
||||
}
|
||||
if (_scroll) {
|
||||
const auto scrollBottom = (_scroll->scrollTop() + _scroll->height());
|
||||
const auto atBottom = (scrollBottom >= _messages->height());
|
||||
const auto bottom = _bottom - _pinnedScrollSkip;
|
||||
|
||||
const auto min = std::min(height, _availableHeight);
|
||||
_scroll->setGeometry(_left, _bottom - min, _width, min);
|
||||
const auto height = _views.empty()
|
||||
? 0
|
||||
: (_views.back().top + _views.back().height);
|
||||
_messages->resize(_width, height);
|
||||
|
||||
if (atBottom) {
|
||||
_scroll->scrollToY(std::max(height - _scroll->height(), 0));
|
||||
const auto min = std::min(height, _availableHeight);
|
||||
_scroll->setGeometry(_left, bottom - min, _width, min);
|
||||
|
||||
if (atBottom) {
|
||||
_scroll->scrollToY(std::max(height - _scroll->height(), 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -909,7 +1309,7 @@ void MessagesUi::move(int left, int bottom, int width, int availableHeight) {
|
||||
_bottom = bottom;
|
||||
_width = width;
|
||||
_availableHeight = availableHeight;
|
||||
applyWidth();
|
||||
applyGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
|
||||
private:
|
||||
struct MessageView;
|
||||
struct PinnedView;
|
||||
struct PayedBg {
|
||||
PayedBg(const Ui::StarsColoring &coloring);
|
||||
|
||||
@@ -81,6 +82,8 @@ private:
|
||||
int stars);
|
||||
void updateMessageSize(MessageView &entry);
|
||||
bool updateMessageHeight(MessageView &entry);
|
||||
void updatePinnedSize(PinnedView &entry);
|
||||
bool updatePinnedWidth(PinnedView &entry);
|
||||
void animateMessageSent(MessageView &entry);
|
||||
void repaintMessage(MsgId id);
|
||||
void recountHeights(std::vector<MessageView>::iterator i, int top);
|
||||
@@ -92,10 +95,23 @@ private:
|
||||
void updateReactionPosition(MessageView &entry);
|
||||
void removeReaction(not_null<Ui::RpWidget*> widget);
|
||||
void setupMessagesWidget();
|
||||
void applyWidth();
|
||||
|
||||
void togglePinned(PinnedView &entry, bool shown);
|
||||
void repaintPinned(MsgId id);
|
||||
void recountWidths(std::vector<PinnedView>::iterator i, int left);
|
||||
void appendPinned(const Message &data);
|
||||
void setupPinnedWidget();
|
||||
|
||||
void applyGeometry();
|
||||
void applyGeometryToPinned();
|
||||
void updateGeometries();
|
||||
[[nodiscard]] int countPinnedScrollSkip(const PinnedView &entry) const;
|
||||
void setPinnedScrollSkip(int skip);
|
||||
|
||||
void updateTopFade();
|
||||
void updateBottomFade();
|
||||
void updateLeftFade();
|
||||
void updateRightFade();
|
||||
|
||||
const not_null<QWidget*> _parent;
|
||||
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||
@@ -105,20 +121,31 @@ private:
|
||||
Ui::RpWidget *_messages = nullptr;
|
||||
QImage _canvas;
|
||||
|
||||
std::unique_ptr<Ui::ElasticScroll> _pinnedScroll;
|
||||
Ui::RpWidget *_pinned = nullptr;
|
||||
QImage _pinnedCanvas;
|
||||
int _pinnedScrollSkip = 0;
|
||||
|
||||
std::vector<MessageView> _views;
|
||||
style::complex_color _messageBg;
|
||||
Ui::RoundRect _messageBgRect;
|
||||
|
||||
std::vector<PinnedView> _pinnedViews;
|
||||
base::flat_map<uint64, std::unique_ptr<PayedBg>> _bgs;
|
||||
|
||||
QPoint _reactionBasePosition;
|
||||
rpl::lifetime _effectsLifetime;
|
||||
|
||||
Ui::Animations::Simple _topFadeAnimation;
|
||||
Ui::Animations::Simple _bottomFadeAnimation;
|
||||
//Ui::Animations::Simple _topFadeAnimation;
|
||||
//Ui::Animations::Simple _bottomFadeAnimation;
|
||||
//Ui::Animations::Simple _leftFadeAnimation;
|
||||
//Ui::Animations::Simple _rightFadeAnimation;
|
||||
int _fadeHeight = 0;
|
||||
int _fadeWidth = 0;
|
||||
bool _topFadeShown = false;
|
||||
bool _bottomFadeShown = false;
|
||||
bool _leftFadeShown = false;
|
||||
bool _rightFadeShown = false;
|
||||
bool _streamMode = false;
|
||||
|
||||
int _left = 0;
|
||||
|
||||
Reference in New Issue
Block a user