mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Implement suggested reaction count.
This commit is contained in:
parent
f3db7e636b
commit
5d5cae7860
8 changed files with 150 additions and 27 deletions
|
@ -411,16 +411,28 @@ Data::ReactionId Story::sentReactionId() const {
|
|||
void Story::setReactionId(Data::ReactionId id) {
|
||||
if (_sentReactionId != id) {
|
||||
const auto wasEmpty = _sentReactionId.empty();
|
||||
changeSuggestedReactionCount(_sentReactionId, -1);
|
||||
_sentReactionId = id;
|
||||
auto flags = UpdateFlag::Reaction | UpdateFlag();
|
||||
changeSuggestedReactionCount(id, 1);
|
||||
|
||||
if (_views.known && _sentReactionId.empty() != wasEmpty) {
|
||||
const auto delta = wasEmpty ? 1 : -1;
|
||||
if (_views.reactions + delta >= 0) {
|
||||
_views.reactions += delta;
|
||||
flags |= UpdateFlag::ViewsChanged;
|
||||
}
|
||||
}
|
||||
session().changes().storyUpdated(this, flags);
|
||||
session().changes().storyUpdated(this, UpdateFlag::Reaction);
|
||||
}
|
||||
}
|
||||
|
||||
void Story::changeSuggestedReactionCount(Data::ReactionId id, int delta) {
|
||||
if (id.empty() || !_peer->isChannel()) {
|
||||
return;
|
||||
}
|
||||
for (auto &suggested : _suggestedReactions) {
|
||||
if (suggested.reaction == id && suggested.count + delta >= 0) {
|
||||
suggested.count += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -539,11 +551,13 @@ void Story::applyFields(
|
|||
auto reactions = _views.reactions;
|
||||
auto viewers = std::vector<not_null<PeerData*>>();
|
||||
auto viewsKnown = _views.known;
|
||||
auto reactionsCounts = base::flat_map<Data::ReactionId, int>();
|
||||
if (const auto info = data.vviews()) {
|
||||
views = info->data().vviews_count().v;
|
||||
reactions = info->data().vreactions_count().value_or_empty();
|
||||
const auto &data = info->data();
|
||||
views = data.vviews_count().v;
|
||||
reactions = data.vreactions_count().value_or_empty();
|
||||
viewsKnown = true;
|
||||
if (const auto list = info->data().vrecent_viewers()) {
|
||||
if (const auto list = data.vrecent_viewers()) {
|
||||
viewers.reserve(list->v.size());
|
||||
auto &owner = _peer->owner();
|
||||
auto &&cut = list->v
|
||||
|
@ -552,8 +566,33 @@ void Story::applyFields(
|
|||
viewers.push_back(owner.peer(peerFromUser(id)));
|
||||
}
|
||||
}
|
||||
auto total = 0;
|
||||
if (const auto list = data.vreactions()) {
|
||||
reactionsCounts.reserve(list->v.size());
|
||||
for (const auto &reaction : list->v) {
|
||||
const auto &data = reaction.data();
|
||||
const auto id = Data::ReactionFromMTP(data.vreaction());
|
||||
const auto count = data.vcount().v;
|
||||
reactionsCounts[id] = count;
|
||||
total += count;
|
||||
}
|
||||
}
|
||||
if (!reaction.empty()) {
|
||||
if (auto &mine = reactionsCounts[reaction]; !mine) {
|
||||
mine = 1;
|
||||
++total;
|
||||
}
|
||||
}
|
||||
if (reactions < total) {
|
||||
reactions = total;
|
||||
}
|
||||
} else {
|
||||
viewers = _recentViewers;
|
||||
for (const auto &suggested : _suggestedReactions) {
|
||||
if (const auto count = suggested.count) {
|
||||
reactionsCounts[suggested.reaction] = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto locations = std::vector<StoryLocation>();
|
||||
auto suggestedReactions = std::vector<SuggestedReaction>();
|
||||
|
@ -563,7 +602,11 @@ void Story::applyFields(
|
|||
for (const auto &area : areas->v) {
|
||||
if (const auto location = ParseLocation(area)) {
|
||||
locations.push_back(*location);
|
||||
} else if (const auto reaction = ParseSuggestedReaction(area)) {
|
||||
} else if (auto reaction = ParseSuggestedReaction(area)) {
|
||||
const auto i = reactionsCounts.find(reaction->reaction);
|
||||
if (i != end(reactionsCounts)) {
|
||||
reaction->count = i->second;
|
||||
}
|
||||
suggestedReactions.push_back(*reaction);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ struct StoryLocation {
|
|||
struct SuggestedReaction {
|
||||
StoryArea area;
|
||||
Data::ReactionId reaction;
|
||||
int count = 0;
|
||||
bool flipped = false;
|
||||
bool dark = false;
|
||||
|
||||
|
@ -180,6 +181,7 @@ public:
|
|||
[[nodiscard]] TimeId lastUpdateTime() const;
|
||||
|
||||
private:
|
||||
void changeSuggestedReactionCount(Data::ReactionId id, int delta);
|
||||
void applyFields(
|
||||
StoryMedia media,
|
||||
const MTPDstoryItem &data,
|
||||
|
|
|
@ -892,6 +892,9 @@ bool Controller::changeShown(Data::Story *story) {
|
|||
const auto id = story ? story->fullId() : FullStoryId();
|
||||
const auto session = story ? &story->session() : nullptr;
|
||||
const auto sessionChanged = (_session != session);
|
||||
|
||||
updateAreas(story);
|
||||
|
||||
if (_shown == id && !sessionChanged) {
|
||||
return false;
|
||||
}
|
||||
|
@ -915,21 +918,6 @@ bool Controller::changeShown(Data::Story *story) {
|
|||
Data::Stories::Polling::Viewer);
|
||||
}
|
||||
|
||||
const auto &locations = story
|
||||
? story->locations()
|
||||
: std::vector<Data::StoryLocation>();
|
||||
const auto &suggestedReactions = story
|
||||
? story->suggestedReactions()
|
||||
: std::vector<Data::SuggestedReaction>();
|
||||
if (_locations != locations) {
|
||||
_locations = locations;
|
||||
_areas.clear();
|
||||
}
|
||||
if (_suggestedReactions != suggestedReactions) {
|
||||
_suggestedReactions = suggestedReactions;
|
||||
_areas.clear();
|
||||
}
|
||||
|
||||
_viewed = false;
|
||||
invalidate_weak_ptrs(&_viewsLoadGuard);
|
||||
_reactions->hide();
|
||||
|
@ -963,6 +951,7 @@ void Controller::subscribeToSession() {
|
|||
_session->changes().storyUpdates(
|
||||
Data::StoryUpdate::Flag::Edited
|
||||
| Data::StoryUpdate::Flag::ViewsChanged
|
||||
| Data::StoryUpdate::Flag::Reaction
|
||||
) | rpl::filter([=](const Data::StoryUpdate &update) {
|
||||
return (update.story == this->story());
|
||||
}) | rpl::start_with_next([=](const Data::StoryUpdate &update) {
|
||||
|
@ -977,6 +966,7 @@ void Controller::subscribeToSession() {
|
|||
.self = update.story->peer()->isSelf(),
|
||||
.channel = update.story->peer()->isChannel(),
|
||||
});
|
||||
updateAreas(update.story);
|
||||
}
|
||||
}, _sessionLifetime);
|
||||
_sessionLifetime.add([=] {
|
||||
|
@ -984,6 +974,41 @@ void Controller::subscribeToSession() {
|
|||
});
|
||||
}
|
||||
|
||||
void Controller::updateAreas(Data::Story *story) {
|
||||
const auto &locations = story
|
||||
? story->locations()
|
||||
: std::vector<Data::StoryLocation>();
|
||||
const auto &suggestedReactions = story
|
||||
? story->suggestedReactions()
|
||||
: std::vector<Data::SuggestedReaction>();
|
||||
if (_locations != locations) {
|
||||
_locations = locations;
|
||||
_areas.clear();
|
||||
}
|
||||
const auto reactionsCount = int(suggestedReactions.size());
|
||||
if (_suggestedReactions.size() == reactionsCount && !_areas.empty()) {
|
||||
for (auto i = 0; i != reactionsCount; ++i) {
|
||||
const auto count = suggestedReactions[i].count;
|
||||
if (_suggestedReactions[i].count != count) {
|
||||
_suggestedReactions[i].count = count;
|
||||
_areas[i + _locations.size()].reaction->updateCount(count);
|
||||
}
|
||||
if (_suggestedReactions[i] != suggestedReactions[i]) {
|
||||
_suggestedReactions = suggestedReactions;
|
||||
_areas.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (_suggestedReactions != suggestedReactions) {
|
||||
_suggestedReactions = suggestedReactions;
|
||||
_areas.clear();
|
||||
}
|
||||
if (_areas.empty() || _suggestedReactions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PauseState Controller::pauseState() const {
|
||||
const auto inactive = !_windowActive
|
||||
|| _replyActive
|
||||
|
|
|
@ -247,6 +247,7 @@ private:
|
|||
const std::vector<Data::StoriesSourceInfo> &lists,
|
||||
int index);
|
||||
|
||||
void updateAreas(Data::Story *story);
|
||||
void reactionChosen(ReactionsMode mode, ChosenReaction chosen);
|
||||
|
||||
const not_null<Delegate*> _delegate;
|
||||
|
|
|
@ -27,6 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "media/stories/media_stories_controller.h"
|
||||
#include "lang/lang_tag.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/effects/emoji_fly_animation.h"
|
||||
#include "ui/effects/path_shift_gradient.h"
|
||||
|
@ -55,6 +56,7 @@ constexpr auto kSuggestedTailSmallOffset = 0.697;
|
|||
constexpr auto kSuggestedTailBigRotation = -42.29;
|
||||
constexpr auto kSuggestedTailSmallRotation = -40.87;
|
||||
constexpr auto kSuggestedReactionSize = 0.7;
|
||||
constexpr auto kSuggestedWithCountSize = 0.55;
|
||||
|
||||
class ReactionView final
|
||||
: public Ui::RpWidget
|
||||
|
@ -67,6 +69,7 @@ public:
|
|||
const Data::SuggestedReaction &reaction);
|
||||
|
||||
void setAreaGeometry(QRect geometry) override;
|
||||
void updateCount(int count) override;
|
||||
|
||||
private:
|
||||
using Element = HistoryView::Element;
|
||||
|
@ -85,6 +88,8 @@ private:
|
|||
std::unique_ptr<Ui::PathShiftGradient> _pathGradient;
|
||||
AdminLog::OwnedItem _fake;
|
||||
QImage _background;
|
||||
QString _countShort;
|
||||
Ui::Text::String _counter;
|
||||
QRectF _bubbleGeometry;
|
||||
int _size = 0;
|
||||
int _mediaLeft = 0;
|
||||
|
@ -183,6 +188,9 @@ ReactionView::ReactionView(
|
|||
}
|
||||
}, lifetime());
|
||||
|
||||
_data.count = 0;
|
||||
updateCount(reaction.count);
|
||||
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
show();
|
||||
}
|
||||
|
@ -202,6 +210,24 @@ void ReactionView::setAreaGeometry(QRect geometry) {
|
|||
setGeometry(geometry.marginsAdded({ add, add, add, add }));
|
||||
}
|
||||
|
||||
void ReactionView::updateCount(int count) {
|
||||
if (_data.count == count) {
|
||||
return;
|
||||
}
|
||||
_data.count = count;
|
||||
const auto countShort = Lang::FormatCountToShort(count).string;
|
||||
if (_countShort == countShort) {
|
||||
return;
|
||||
}
|
||||
_countShort = countShort;
|
||||
if (!count) {
|
||||
_counter = {};
|
||||
} else {
|
||||
_counter = { st::storiesLikeCountStyle, _countShort };
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
not_null<HistoryView::ElementDelegate*> ReactionView::delegate() {
|
||||
return static_cast<HistoryView::ElementDelegate*>(this);
|
||||
}
|
||||
|
@ -215,15 +241,34 @@ void ReactionView::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
p.drawImage(0, 0, _background);
|
||||
|
||||
const auto counter = !_counter.isEmpty();
|
||||
const auto scale = counter
|
||||
? kSuggestedWithCountSize
|
||||
: kSuggestedReactionSize;
|
||||
const auto counterSkip = counter
|
||||
? ((kSuggestedReactionSize - kSuggestedWithCountSize)
|
||||
* _mediaHeight / 2)
|
||||
: 0;
|
||||
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
p.translate(_bubbleGeometry.center());
|
||||
p.scale(
|
||||
kSuggestedReactionSize * _bubbleGeometry.width() / _mediaWidth,
|
||||
kSuggestedReactionSize * _bubbleGeometry.height() / _mediaHeight);
|
||||
scale * _bubbleGeometry.width() / _mediaWidth,
|
||||
scale * _bubbleGeometry.height() / _mediaHeight);
|
||||
p.rotate(_data.area.rotation);
|
||||
p.translate(
|
||||
-(_mediaLeft + (_mediaWidth / 2)),
|
||||
-(_mediaTop + (_mediaHeight / 2)));
|
||||
-(_mediaTop + (_mediaHeight / 2) + counterSkip));
|
||||
|
||||
if (counter) {
|
||||
p.setPen(_data.dark ? Qt::white : Qt::black);
|
||||
_counter.draw(
|
||||
p,
|
||||
_mediaLeft,
|
||||
_mediaTop + _mediaHeight,
|
||||
_mediaWidth,
|
||||
style::al_top);
|
||||
}
|
||||
|
||||
auto context = Ui::ChatPaintContext{
|
||||
.st = _chatStyle.get(),
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
virtual ~SuggestedReactionView() = default;
|
||||
|
||||
virtual void setAreaGeometry(QRect geometry) = 0;
|
||||
virtual void updateCount(int count) = 0;
|
||||
};
|
||||
|
||||
class Reactions final {
|
||||
|
|
|
@ -323,7 +323,7 @@ void RecentViews::setupViewsReactions() {
|
|||
) | rpl::start_with_next([=](int width) {
|
||||
width += width
|
||||
? st::storiesLikesTextRightSkip
|
||||
: st::storiesLieksEmptyRightSkip;
|
||||
: st::storiesLikesEmptyRightSkip;
|
||||
_likeWrap->resize(likes->x() + width, _likeIcon->height());
|
||||
updateViewsReactionsGeometry();
|
||||
}, _likeWrap->lifetime());
|
||||
|
|
|
@ -1007,4 +1007,10 @@ storiesLikesText: FlatLabel(defaultFlatLabel) {
|
|||
}
|
||||
storiesLikesTextPosition: point(41px, 14px);
|
||||
storiesLikesTextRightSkip: 8px;
|
||||
storiesLieksEmptyRightSkip: 2px;
|
||||
storiesLikesEmptyRightSkip: 2px;
|
||||
|
||||
storiesLikeCountStyle: TextStyle(defaultTextStyle) {
|
||||
font: font(32px semibold);
|
||||
linkFont: font(32px semibold);
|
||||
linkFontOver: font(32px semibold underline);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue