Animate pinned duration.

This commit is contained in:
John Preston
2025-10-24 18:07:17 +04:00
parent 74a676026f
commit 8e30ee1192
4 changed files with 104 additions and 33 deletions

View File

@@ -50,6 +50,17 @@ constexpr auto kMaxShownVideoStreamMessages = 100;
return result;
}
[[nodiscard]] TimeId PinFinishDate(TimeId date, int stars) {
if (!date || !stars) {
return 0;
}
return date + (Ui::StarsColoringForCount(stars).minutesPin * TimeId(60));
}
[[nodiscard]] TimeId PinFinishDate(const Message &message) {
return PinFinishDate(message.date, message.stars);
}
[[nodiscard]] std::optional<PeerId> MaybeShownPeer(
uint32 privacySet,
PeerId shownPeer) {
@@ -250,6 +261,7 @@ void Messages::sent(uint64 randomId, const MTP::Response &response) {
const auto i = ranges::find(_messages, realId, &Message::id);
if (i != end(_messages) && !i->date) {
i->date = Api::UnixtimeFromMsgId(response.outerMsgId);
i->pinFinishDate = PinFinishDate(*i);
checkDestroying(true);
}
}
@@ -271,6 +283,7 @@ void Messages::sent(uint64 randomId, MsgId realId) {
const auto i = ranges::find(_messages, realId, &Message::id);
if (i != end(_messages) && !i->date) {
i->date = base::unixtime::now();
i->pinFinishDate = PinFinishDate(*i);
checkDestroying(true);
}
});
@@ -292,6 +305,7 @@ void Messages::received(
const auto me2 = _call->messagesFrom()->id;
if (((fromId == me1) || (fromId == me2)) && !i->date) {
i->date = date;
i->pinFinishDate = PinFinishDate(*i);
checkDestroying(true);
}
return;
@@ -312,6 +326,7 @@ void Messages::received(
_messages.push_back({
.id = id,
.date = date,
.pinFinishDate = PinFinishDate(date, stars),
.peer = peer->owner().peer(peerFromMTP(from)),
.text = Ui::Text::Filtered(
Api::ParseTextWithEntities(&peer->session(), message),
@@ -407,6 +422,7 @@ void Messages::failed(uint64 randomId, const MTP::Response &response) {
const auto j = ranges::find(_messages, localId, &Message::id);
if (j != end(_messages) && !j->date) {
j->date = Api::UnixtimeFromMsgId(response.outerMsgId);
j->stars = 0;
j->failed = true;
checkDestroying(true);
}

View File

@@ -33,6 +33,7 @@ namespace Calls::Group {
struct Message {
MsgId id = 0;
TimeId date = 0;
TimeId pinFinishDate = 0;
not_null<PeerData*> peer;
TextWithEntities text;
int stars = 0;

View File

@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/group/calls_group_messages_ui.h"
#include "base/unixtime.h"
#include "boxes/peers/prepare_short_info_box.h"
#include "boxes/premium_preview_box.h"
#include "calls/group/ui/calls_group_stars_coloring.h"
@@ -178,6 +179,8 @@ struct MessagesUi::PinnedView {
Ui::Animations::Simple toggleAnimation;
Ui::PeerUserpicView view;
Ui::Text::String text;
crl::time duration = 0;
crl::time end = 0;
int stars = 0;
int top = 0;
int width = 0;
@@ -185,11 +188,14 @@ struct MessagesUi::PinnedView {
int height = 0;
int realWidth = 0;
bool removed = false;
bool requiresSmooth = false;
};
MessagesUi::PayedBg::PayedBg(const Ui::StarsColoring &coloring)
: color(Ui::ColorFromSerialized(coloring.bg2))
, rounded(CountMessageRadius(), color.color()) {
: color1(Ui::ColorFromSerialized(coloring.bg1))
, color2(Ui::ColorFromSerialized(coloring.bg2))
, rounded1(CountMessageRadius(), color1.color())
, rounded2(CountMessageRadius(), color2.color()) {
}
MessagesUi::MessagesUi(
@@ -227,6 +233,7 @@ void MessagesUi::setupList(
if (!shown) {
list.clear();
}
const auto now = base::unixtime::now();
auto from = begin(list);
auto till = end(list);
for (auto &entry : _views) {
@@ -250,14 +257,7 @@ void MessagesUi::setupList(
animateMessageSent(entry);
}
if (i == from) {
if (i->stars
&& i->date
&& !ranges::contains(
_pinnedViews,
i->id,
&PinnedView::id)) {
appendPinned(*i);
}
appendPinned(*i, now);
++from;
}
}
@@ -268,9 +268,7 @@ void MessagesUi::setupList(
addedSendingToBottom = true;
}
appendMessage(*i);
if (i->stars && i->date) {
appendPinned(*i);
}
appendPinned(*i, now);
}
}
if (addedSendingToBottom) {
@@ -383,6 +381,9 @@ void MessagesUi::updatePinnedSize(PinnedView &entry) {
const auto skip = st::groupCallMessageSkip;
entry.realWidth = skip + leftSkip + inner + padding.right();
const auto ratio = style::DevicePixelRatio();
entry.requiresSmooth = (entry.realWidth * ratio * 1000 > entry.duration);
}
bool MessagesUi::updatePinnedWidth(PinnedView &entry) {
@@ -619,8 +620,16 @@ void MessagesUi::recountWidths(
}
}
void MessagesUi::appendPinned(const Message &data) {
if (!_pinnedScroll) {
void MessagesUi::appendPinned(const Message &data, TimeId now) {
if (!data.date
|| data.pinFinishDate <= data.date
|| data.pinFinishDate <= now
|| ranges::contains(
_pinnedViews,
data.id,
&PinnedView::id)) {
return;
} else if (!_pinnedScroll) {
setupPinnedWidget();
}
@@ -631,10 +640,16 @@ void MessagesUi::appendPinned(const Message &data) {
data.stars,
ranges::greater(),
&PinnedView::stars);
const auto left = (i == end(_pinnedViews)) ? 0 : i->left;
const auto left = (i != end(_pinnedViews))
? i->left
: _pinnedViews.empty()
? 0
: (_pinnedViews.back().left + _pinnedViews.back().width);
auto &entry = *_pinnedViews.insert(i, PinnedView{
.id = data.id,
.from = peer,
.duration = (data.pinFinishDate - data.date) * crl::time(1000),
.end = crl::now() + (data.pinFinishDate - now) * crl::time(1000),
.stars = data.stars,
.left = left,
});
@@ -945,7 +960,7 @@ void MessagesUi::setupMessagesWidget() {
bg = std::make_unique<PayedBg>(coloring);
}
p.setOpacity(kColoredMessageBgOpacity);
bg->rounded.paint(p, { x, y, width, use });
bg->rounded2.paint(p, { x, y, width, use });
p.setOpacity(1.);
}
@@ -1077,6 +1092,42 @@ void MessagesUi::setupPinnedWidget() {
updateRightFade();
}, scroll->lifetime());
struct Animation {
base::Timer seconds;
Ui::Animations::Simple smooth;
bool requiresSmooth = false;
};
const auto animation = _pinned->lifetime().make_state<Animation>();
animation->seconds.setCallback([=] {
const auto now = crl::now();
auto smooth = false;
auto off = base::flat_set<MsgId>();
for (auto &entry : _pinnedViews) {
if (entry.removed) {
continue;
} else if (entry.end <= now) {
off.emplace(entry.id);
entry.requiresSmooth = false;
} else if (entry.requiresSmooth) {
smooth = true;
}
}
if (smooth && !anim::Disabled()) {
animation->smooth.start([=] {
_pinned->update();
}, 0., 1., 900.);
} else {
_pinned->update();
}
for (const auto &id : off) {
const auto i = ranges::find(_pinnedViews, id, &PinnedView::id);
if (i != end(_pinnedViews)) {
togglePinned(*i, false);
}
}
});
animation->seconds.callEach(crl::time(1000));
_pinned->paintRequest() | rpl::start_with_next([=](QRect clip) {
const auto start = scroll->scrollLeft();
const auto end = start + scroll->width();
@@ -1127,9 +1178,18 @@ void MessagesUi::setupPinnedWidget() {
if (!bg) {
bg = std::make_unique<PayedBg>(coloring);
}
p.setOpacity(kColoredMessageBgOpacity);
bg->rounded.paint(p, { x, y, use, height });
p.setOpacity(1.);
const auto still = (entry.end - now) / float64(entry.duration);
const auto part = int(base::SafeRound(still * use));
const auto line = st::lineWidth;
if (part > 0) {
p.setClipRect(x - line, y, part + line, height);
bg->rounded1.paint(p, { x, y, use, height });
}
if (part < use) {
p.setClipRect(x + part, y, use - part + line, height);
bg->rounded2.paint(p, { x, y, use, height });
}
p.setClipping(false);
const auto userpicSize = st::groupCallUserpic;
const auto userpicPadding = st::groupCallUserpicPadding;
@@ -1150,15 +1210,8 @@ void MessagesUi::setupPinnedWidget() {
p.setPen(st::white);
entry.text.draw(p, {
.position = {
x + leftSkip,
y + padding.top(),
},
.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();
@@ -1231,7 +1284,6 @@ void MessagesUi::applyGeometryToPinned() {
auto left = 0;
for (auto &entry : _pinnedViews) {
entry.left = left;
updatePinnedSize(entry);
updatePinnedWidth(entry);
left += entry.width;

View File

@@ -64,10 +64,12 @@ private:
struct MessageView;
struct PinnedView;
struct PayedBg {
PayedBg(const Ui::StarsColoring &coloring);
explicit PayedBg(const Ui::StarsColoring &coloring);
style::owned_color color;
Ui::RoundRect rounded;
style::owned_color color1;
style::owned_color color2;
Ui::RoundRect rounded1;
Ui::RoundRect rounded2;
};
void setupList(
@@ -99,7 +101,7 @@ private:
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 appendPinned(const Message &data, TimeId now);
void setupPinnedWidget();
void applyGeometry();