mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Show reposts / forwards in story viewers.
This commit is contained in:
parent
8e92778b62
commit
d87a0a2d25
15 changed files with 188 additions and 39 deletions
|
@ -1836,6 +1836,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
"lng_sponsored_message_title" = "Sponsored";
|
"lng_sponsored_message_title" = "Sponsored";
|
||||||
"lng_recommended_message_title" = "Recommended";
|
"lng_recommended_message_title" = "Recommended";
|
||||||
"lng_edited" = "edited";
|
"lng_edited" = "edited";
|
||||||
|
"lng_commented" = "commented";
|
||||||
"lng_edited_date" = "Edited: {date}";
|
"lng_edited_date" = "Edited: {date}";
|
||||||
"lng_sent_date" = "Sent: {date}";
|
"lng_sent_date" = "Sent: {date}";
|
||||||
"lng_views_tooltip#one" = "Views: {count}";
|
"lng_views_tooltip#one" = "Views: {count}";
|
||||||
|
|
|
@ -399,7 +399,7 @@ void PublicForwards::request(
|
||||||
recentList.push_back({ .messageId = { peerId, msgId } });
|
recentList.push_back({ .messageId = { peerId, msgId } });
|
||||||
}
|
}
|
||||||
}, [&](const MTPDpublicForwardStory &data) {
|
}, [&](const MTPDpublicForwardStory &data) {
|
||||||
const auto story = owner.stories().applyFromWebpage(
|
const auto story = owner.stories().applySingle(
|
||||||
peerFromMTP(data.vpeer()),
|
peerFromMTP(data.vpeer()),
|
||||||
data.vstory());
|
data.vstory());
|
||||||
if (story) {
|
if (story) {
|
||||||
|
|
|
@ -3416,7 +3416,7 @@ void Session::webpageApplyFields(
|
||||||
data.vid().v,
|
data.vid().v,
|
||||||
};
|
};
|
||||||
if (const auto embed = data.vstory()) {
|
if (const auto embed = data.vstory()) {
|
||||||
story = stories().applyFromWebpage(
|
story = stories().applySingle(
|
||||||
peerFromMTP(data.vpeer()),
|
peerFromMTP(data.vpeer()),
|
||||||
*embed);
|
*embed);
|
||||||
} else if (const auto maybe = stories().lookup(storyId)) {
|
} else if (const auto maybe = stories().lookup(storyId)) {
|
||||||
|
|
|
@ -220,7 +220,7 @@ void Stories::apply(not_null<PeerData*> peer, const MTPPeerStories *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Story *Stories::applyFromWebpage(PeerId peerId, const MTPstoryItem &story) {
|
Story *Stories::applySingle(PeerId peerId, const MTPstoryItem &story) {
|
||||||
const auto idDates = parseAndApply(
|
const auto idDates = parseAndApply(
|
||||||
_owner->peer(peerId),
|
_owner->peer(peerId),
|
||||||
story,
|
story,
|
||||||
|
@ -1374,6 +1374,8 @@ void Stories::sendViewsSliceRequest() {
|
||||||
auto slice = StoryViews{
|
auto slice = StoryViews{
|
||||||
.nextOffset = data.vnext_offset().value_or_empty(),
|
.nextOffset = data.vnext_offset().value_or_empty(),
|
||||||
.reactions = data.vreactions_count().v,
|
.reactions = data.vreactions_count().v,
|
||||||
|
.forwards = data.vforwards_count().v,
|
||||||
|
.views = data.vviews_count().v,
|
||||||
.total = data.vcount().v,
|
.total = data.vcount().v,
|
||||||
};
|
};
|
||||||
_owner->processUsers(data.vusers());
|
_owner->processUsers(data.vusers());
|
||||||
|
@ -1387,8 +1389,27 @@ void Stories::sendViewsSliceRequest() {
|
||||||
: Data::ReactionId()),
|
: Data::ReactionId()),
|
||||||
.date = data.vdate().v,
|
.date = data.vdate().v,
|
||||||
});
|
});
|
||||||
}, [](const auto &) {
|
}, [&](const MTPDstoryViewPublicRepost &data) {
|
||||||
|
const auto story = applySingle(
|
||||||
|
peerFromMTP(data.vpeer_id()),
|
||||||
|
data.vstory());
|
||||||
|
if (story) {
|
||||||
|
slice.list.push_back({
|
||||||
|
.peer = story->peer(),
|
||||||
|
.repostId = story->id(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [&](const MTPDstoryViewPublicForward &data) {
|
||||||
|
const auto item = _owner->addNewMessage(
|
||||||
|
data.vmessage(),
|
||||||
|
{},
|
||||||
|
NewMessageType::Existing);
|
||||||
|
if (item) {
|
||||||
|
slice.list.push_back({
|
||||||
|
.peer = item->history()->peer,
|
||||||
|
.forwardId = item->id,
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const auto fullId = FullStoryId{
|
const auto fullId = FullStoryId{
|
||||||
|
|
|
@ -149,7 +149,7 @@ public:
|
||||||
void apply(const MTPDupdateReadStories &data);
|
void apply(const MTPDupdateReadStories &data);
|
||||||
void apply(const MTPStoriesStealthMode &stealthMode);
|
void apply(const MTPStoriesStealthMode &stealthMode);
|
||||||
void apply(not_null<PeerData*> peer, const MTPPeerStories *data);
|
void apply(not_null<PeerData*> peer, const MTPPeerStories *data);
|
||||||
Story *applyFromWebpage(PeerId peerId, const MTPstoryItem &story);
|
Story *applySingle(PeerId peerId, const MTPstoryItem &story);
|
||||||
void loadAround(FullStoryId id, StoriesContext context);
|
void loadAround(FullStoryId id, StoriesContext context);
|
||||||
|
|
||||||
const StoriesSource *source(PeerId id) const;
|
const StoriesSource *source(PeerId id) const;
|
||||||
|
|
|
@ -157,6 +157,13 @@ using UpdateFlag = StoryUpdate::Flag;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool RepostModified(const MTPDstoryItem &data) {
|
||||||
|
if (const auto forwarded = data.vfwd_from()) {
|
||||||
|
return forwarded->data().is_modified();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class StoryPreload::LoadTask final : private Storage::DownloadMtprotoTask {
|
class StoryPreload::LoadTask final : private Storage::DownloadMtprotoTask {
|
||||||
|
@ -272,7 +279,8 @@ Story::Story(
|
||||||
, _repostSourceName(RepostSourceName(data))
|
, _repostSourceName(RepostSourceName(data))
|
||||||
, _repostSourceId(RepostSourceId(data))
|
, _repostSourceId(RepostSourceId(data))
|
||||||
, _date(data.vdate().v)
|
, _date(data.vdate().v)
|
||||||
, _expires(data.vexpire_date().v) {
|
, _expires(data.vexpire_date().v)
|
||||||
|
, _repostModified(RepostModified(data)) {
|
||||||
applyFields(std::move(media), data, now, true);
|
applyFields(std::move(media), data, now, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,10 +513,18 @@ const StoryViews &Story::viewsList() const {
|
||||||
return _views;
|
return _views;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Story::views() const {
|
int Story::interactions() const {
|
||||||
return _views.total;
|
return _views.total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Story::views() const {
|
||||||
|
return _views.views;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Story::forwards() const {
|
||||||
|
return _views.forwards;
|
||||||
|
}
|
||||||
|
|
||||||
int Story::reactions() const {
|
int Story::reactions() const {
|
||||||
return _views.reactions;
|
return _views.reactions;
|
||||||
}
|
}
|
||||||
|
@ -517,8 +533,12 @@ void Story::applyViewsSlice(
|
||||||
const QString &offset,
|
const QString &offset,
|
||||||
const StoryViews &slice) {
|
const StoryViews &slice) {
|
||||||
const auto changed = (_views.reactions != slice.reactions)
|
const auto changed = (_views.reactions != slice.reactions)
|
||||||
|
|| (_views.views != slice.views)
|
||||||
|
|| (_views.forwards != slice.forwards)
|
||||||
|| (_views.total != slice.total);
|
|| (_views.total != slice.total);
|
||||||
_views.reactions = slice.reactions;
|
_views.reactions = slice.reactions;
|
||||||
|
_views.forwards = slice.forwards;
|
||||||
|
_views.views = slice.views;
|
||||||
_views.total = slice.total;
|
_views.total = slice.total;
|
||||||
_views.known = true;
|
_views.known = true;
|
||||||
if (offset.isEmpty()) {
|
if (offset.isEmpty()) {
|
||||||
|
@ -536,6 +556,15 @@ void Story::applyViewsSlice(
|
||||||
_views.list,
|
_views.list,
|
||||||
Data::ReactionId(),
|
Data::ReactionId(),
|
||||||
&StoryView::reaction);
|
&StoryView::reaction);
|
||||||
|
_views.forwards = _views.total
|
||||||
|
- ranges::count(
|
||||||
|
_views.list,
|
||||||
|
0,
|
||||||
|
[](const StoryView &view) {
|
||||||
|
return view.repostId
|
||||||
|
? view.repostId
|
||||||
|
: view.forwardId.bare;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto known = int(_views.list.size());
|
const auto known = int(_views.list.size());
|
||||||
|
@ -582,6 +611,7 @@ Story::ViewsCounts Story::parseViewsCounts(
|
||||||
const Data::ReactionId &mine) {
|
const Data::ReactionId &mine) {
|
||||||
auto result = ViewsCounts{
|
auto result = ViewsCounts{
|
||||||
.views = data.vviews_count().v,
|
.views = data.vviews_count().v,
|
||||||
|
.forwards = data.vforwards_count().value_or_empty(),
|
||||||
.reactions = data.vreactions_count().value_or_empty(),
|
.reactions = data.vreactions_count().value_or_empty(),
|
||||||
};
|
};
|
||||||
if (const auto list = data.vrecent_viewers()) {
|
if (const auto list = data.vrecent_viewers()) {
|
||||||
|
@ -660,6 +690,7 @@ void Story::applyFields(
|
||||||
viewsKnown = true;
|
viewsKnown = true;
|
||||||
} else {
|
} else {
|
||||||
counts.views = _views.total;
|
counts.views = _views.total;
|
||||||
|
counts.forwards = _views.forwards;
|
||||||
counts.reactions = _views.reactions;
|
counts.reactions = _views.reactions;
|
||||||
counts.viewers = _recentViewers;
|
counts.viewers = _recentViewers;
|
||||||
for (const auto &suggested : _suggestedReactions) {
|
for (const auto &suggested : _suggestedReactions) {
|
||||||
|
@ -744,15 +775,22 @@ void Story::applyFields(
|
||||||
}
|
}
|
||||||
|
|
||||||
void Story::updateViewsCounts(ViewsCounts &&counts, bool known, bool initial) {
|
void Story::updateViewsCounts(ViewsCounts &&counts, bool known, bool initial) {
|
||||||
const auto viewsChanged = (_views.total != counts.views)
|
const auto total = _views.total
|
||||||
|
? _views.total
|
||||||
|
: (counts.views + counts.forwards);
|
||||||
|
const auto viewsChanged = (_views.total != total)
|
||||||
|
|| (_views.forwards != counts.forwards)
|
||||||
|| (_views.reactions != counts.reactions)
|
|| (_views.reactions != counts.reactions)
|
||||||
|| (_recentViewers != counts.viewers);
|
|| (_recentViewers != counts.viewers);
|
||||||
if (_views.reactions != counts.reactions
|
if (_views.reactions != counts.reactions
|
||||||
|| _views.total != counts.views
|
|| _views.forwards != counts.forwards
|
||||||
|
|| _views.total != total
|
||||||
|| _views.known != known) {
|
|| _views.known != known) {
|
||||||
_views = StoryViews{
|
_views = StoryViews{
|
||||||
.reactions = counts.reactions,
|
.reactions = counts.reactions,
|
||||||
.total = counts.views,
|
.forwards = counts.forwards,
|
||||||
|
.views = counts.views,
|
||||||
|
.total = total,
|
||||||
.known = known,
|
.known = known,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -789,6 +827,10 @@ bool Story::repost() const {
|
||||||
return _repostSourcePeer || !_repostSourceName.isEmpty();
|
return _repostSourcePeer || !_repostSourceName.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Story::repostModified() const {
|
||||||
|
return _repostModified;
|
||||||
|
}
|
||||||
|
|
||||||
PeerData *Story::repostSourcePeer() const {
|
PeerData *Story::repostSourcePeer() const {
|
||||||
return _repostSourcePeer;
|
return _repostSourcePeer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,8 @@ struct StoryMedia {
|
||||||
struct StoryView {
|
struct StoryView {
|
||||||
not_null<PeerData*> peer;
|
not_null<PeerData*> peer;
|
||||||
Data::ReactionId reaction;
|
Data::ReactionId reaction;
|
||||||
|
StoryId repostId = 0;
|
||||||
|
MsgId forwardId = 0;
|
||||||
TimeId date = 0;
|
TimeId date = 0;
|
||||||
|
|
||||||
friend inline bool operator==(StoryView, StoryView) = default;
|
friend inline bool operator==(StoryView, StoryView) = default;
|
||||||
|
@ -70,6 +72,8 @@ struct StoryViews {
|
||||||
std::vector<StoryView> list;
|
std::vector<StoryView> list;
|
||||||
QString nextOffset;
|
QString nextOffset;
|
||||||
int reactions = 0;
|
int reactions = 0;
|
||||||
|
int forwards = 0;
|
||||||
|
int views = 0;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
bool known = false;
|
bool known = false;
|
||||||
};
|
};
|
||||||
|
@ -175,7 +179,9 @@ public:
|
||||||
[[nodiscard]] auto recentViewers() const
|
[[nodiscard]] auto recentViewers() const
|
||||||
-> const std::vector<not_null<PeerData*>> &;
|
-> const std::vector<not_null<PeerData*>> &;
|
||||||
[[nodiscard]] const StoryViews &viewsList() const;
|
[[nodiscard]] const StoryViews &viewsList() const;
|
||||||
|
[[nodiscard]] int interactions() const;
|
||||||
[[nodiscard]] int views() const;
|
[[nodiscard]] int views() const;
|
||||||
|
[[nodiscard]] int forwards() const;
|
||||||
[[nodiscard]] int reactions() const;
|
[[nodiscard]] int reactions() const;
|
||||||
void applyViewsSlice(const QString &offset, const StoryViews &slice);
|
void applyViewsSlice(const QString &offset, const StoryViews &slice);
|
||||||
|
|
||||||
|
@ -191,6 +197,7 @@ public:
|
||||||
[[nodiscard]] TimeId lastUpdateTime() const;
|
[[nodiscard]] TimeId lastUpdateTime() const;
|
||||||
|
|
||||||
[[nodiscard]] bool repost() const;
|
[[nodiscard]] bool repost() const;
|
||||||
|
[[nodiscard]] bool repostModified() const;
|
||||||
[[nodiscard]] PeerData *repostSourcePeer() const;
|
[[nodiscard]] PeerData *repostSourcePeer() const;
|
||||||
[[nodiscard]] QString repostSourceName() const;
|
[[nodiscard]] QString repostSourceName() const;
|
||||||
[[nodiscard]] StoryId repostSourceId() const;
|
[[nodiscard]] StoryId repostSourceId() const;
|
||||||
|
@ -198,6 +205,7 @@ public:
|
||||||
private:
|
private:
|
||||||
struct ViewsCounts {
|
struct ViewsCounts {
|
||||||
int views = 0;
|
int views = 0;
|
||||||
|
int forwards = 0;
|
||||||
int reactions = 0;
|
int reactions = 0;
|
||||||
base::flat_map<Data::ReactionId, int> reactionsCounts;
|
base::flat_map<Data::ReactionId, int> reactionsCounts;
|
||||||
std::vector<not_null<PeerData*>> viewers;
|
std::vector<not_null<PeerData*>> viewers;
|
||||||
|
@ -236,6 +244,7 @@ private:
|
||||||
bool _privacyCloseFriends : 1 = false;
|
bool _privacyCloseFriends : 1 = false;
|
||||||
bool _privacyContacts : 1 = false;
|
bool _privacyContacts : 1 = false;
|
||||||
bool _privacySelectedContacts : 1 = false;
|
bool _privacySelectedContacts : 1 = false;
|
||||||
|
const bool _repostModified : 1 = false;
|
||||||
bool _noForwards : 1 = false;
|
bool _noForwards : 1 = false;
|
||||||
bool _edited : 1 = false;
|
bool _edited : 1 = false;
|
||||||
|
|
||||||
|
|
|
@ -903,7 +903,9 @@ void Controller::show(
|
||||||
_recentViews->show({
|
_recentViews->show({
|
||||||
.list = story->recentViewers(),
|
.list = story->recentViewers(),
|
||||||
.reactions = story->reactions(),
|
.reactions = story->reactions(),
|
||||||
.total = story->views(),
|
.forwards = story->forwards(),
|
||||||
|
.views = story->views(),
|
||||||
|
.total = story->interactions(),
|
||||||
.type = RecentViewsTypeFor(peer),
|
.type = RecentViewsTypeFor(peer),
|
||||||
}, _reactions->likedValue());
|
}, _reactions->likedValue());
|
||||||
if (const auto nowLikeButton = _recentViews->likeButton()) {
|
if (const auto nowLikeButton = _recentViews->likeButton()) {
|
||||||
|
@ -999,7 +1001,9 @@ void Controller::subscribeToSession() {
|
||||||
_recentViews->show({
|
_recentViews->show({
|
||||||
.list = update.story->recentViewers(),
|
.list = update.story->recentViewers(),
|
||||||
.reactions = update.story->reactions(),
|
.reactions = update.story->reactions(),
|
||||||
.total = update.story->views(),
|
.forwards = update.story->forwards(),
|
||||||
|
.views = update.story->views(),
|
||||||
|
.total = update.story->interactions(),
|
||||||
.type = RecentViewsTypeFor(update.story->peer()),
|
.type = RecentViewsTypeFor(update.story->peer()),
|
||||||
});
|
});
|
||||||
updateAreas(update.story);
|
updateAreas(update.story);
|
||||||
|
|
|
@ -256,7 +256,7 @@ struct MadePrivacyBadge {
|
||||||
QString::fromUtf8(" \xE2\x80\xA2 ") + tr::lng_edited(tr::now));
|
QString::fromUtf8(" \xE2\x80\xA2 ") + tr::lng_edited(tr::now));
|
||||||
}
|
}
|
||||||
if (!data.repostFrom.isEmpty()) {
|
if (!data.repostFrom.isEmpty()) {
|
||||||
result.text = QString::fromUtf8("\xC2\xA0\xE2\x80\xA2 ")
|
result.text = QString::fromUtf8("\xE2\x80\xA2 ")
|
||||||
+ result.text;
|
+ result.text;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -500,7 +500,8 @@ void Header::show(HeaderData data) {
|
||||||
_repost->resizeToNaturalWidth(repostAvailable);
|
_repost->resizeToNaturalWidth(repostAvailable);
|
||||||
}
|
}
|
||||||
_repost->move(dateLeft, dateTop);
|
_repost->move(dateLeft, dateTop);
|
||||||
_date->move(dateLeft + _repost->width(), dateTop);
|
const auto space = st::normalFont->spacew;
|
||||||
|
_date->move(dateLeft + _repost->width() + space, dateTop);
|
||||||
} else {
|
} else {
|
||||||
_date->move(dateLeft, dateTop);
|
_date->move(dateLeft, dateTop);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "chat_helpers/compose/compose_show.h"
|
#include "chat_helpers/compose/compose_show.h"
|
||||||
#include "data/stickers/data_custom_emoji.h"
|
#include "data/stickers/data_custom_emoji.h"
|
||||||
#include "data/data_peer.h"
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
#include "data/data_stories.h"
|
#include "data/data_stories.h"
|
||||||
|
#include "history/history_item.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "media/stories/media_stories_controller.h"
|
#include "media/stories/media_stories_controller.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
|
@ -121,6 +123,16 @@ constexpr auto kLoadViewsPages = 2;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] QString ComposeRepostStatus(
|
||||||
|
const QString &date,
|
||||||
|
not_null<Data::Story*> repost) {
|
||||||
|
return date + (repost->repostModified()
|
||||||
|
? (QString::fromUtf8(" \xE2\x80\xA2 ") + tr::lng_edited(tr::now))
|
||||||
|
: !repost->caption().empty()
|
||||||
|
? (QString::fromUtf8(" \xE2\x80\xA2 ") + tr::lng_commented(tr::now))
|
||||||
|
: QString());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
RecentViewsType RecentViewsTypeFor(not_null<PeerData*> peer) {
|
RecentViewsType RecentViewsTypeFor(not_null<PeerData*> peer) {
|
||||||
|
@ -162,6 +174,8 @@ void RecentViews::show(
|
||||||
}
|
}
|
||||||
const auto countersChanged = _text.isEmpty()
|
const auto countersChanged = _text.isEmpty()
|
||||||
|| (_data.total != data.total)
|
|| (_data.total != data.total)
|
||||||
|
|| (_data.views != data.views)
|
||||||
|
|| (_data.forwards != data.forwards)
|
||||||
|| (_data.reactions != data.reactions);
|
|| (_data.reactions != data.reactions);
|
||||||
const auto usersChanged = !_userpics || (_data.list != data.list);
|
const auto usersChanged = !_userpics || (_data.list != data.list);
|
||||||
_data = data;
|
_data = data;
|
||||||
|
@ -194,7 +208,7 @@ void RecentViews::show(
|
||||||
_viewsWrap = nullptr;
|
_viewsWrap = nullptr;
|
||||||
} else {
|
} else {
|
||||||
_viewsCounter = (_data.type == RecentViewsType::Channel)
|
_viewsCounter = (_data.type == RecentViewsType::Channel)
|
||||||
? Lang::FormatCountDecimal(std::max(_data.total, 1))
|
? Lang::FormatCountDecimal(std::max(_data.views, 1))
|
||||||
: tr::lng_stories_cant_reply(tr::now);
|
: tr::lng_stories_cant_reply(tr::now);
|
||||||
_likesCounter = ((_data.type == RecentViewsType::Channel)
|
_likesCounter = ((_data.type == RecentViewsType::Channel)
|
||||||
&& _data.reactions)
|
&& _data.reactions)
|
||||||
|
@ -392,8 +406,8 @@ void RecentViews::updatePartsGeometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecentViews::updateText() {
|
void RecentViews::updateText() {
|
||||||
const auto text = _data.total
|
const auto text = _data.views
|
||||||
? (tr::lng_stories_views(tr::now, lt_count, _data.total)
|
? (tr::lng_stories_views(tr::now, lt_count, _data.views)
|
||||||
+ (_data.reactions
|
+ (_data.reactions
|
||||||
? (u" "_q + QChar(10084) + QString::number(_data.reactions))
|
? (u" "_q + QChar(10084) + QString::number(_data.reactions))
|
||||||
: QString()))
|
: QString()))
|
||||||
|
@ -473,7 +487,21 @@ void RecentViews::addMenuRow(Data::StoryView entry, const QDateTime &now) {
|
||||||
Expects(_menu != nullptr);
|
Expects(_menu != nullptr);
|
||||||
|
|
||||||
const auto peer = entry.peer;
|
const auto peer = entry.peer;
|
||||||
const auto date = Api::FormatReadDate(entry.date, now);
|
const auto repost = entry.repostId
|
||||||
|
? peer->owner().stories().lookup({ peer->id, entry.repostId })
|
||||||
|
: base::make_unexpected(Data::NoStory::Deleted);
|
||||||
|
const auto forward = entry.forwardId
|
||||||
|
? peer->owner().message({ peer->id, entry.forwardId })
|
||||||
|
: nullptr;
|
||||||
|
const auto date = Api::FormatReadDate(
|
||||||
|
repost ? (*repost)->date() : forward ? forward->date() : entry.date,
|
||||||
|
now);
|
||||||
|
const auto type = forward
|
||||||
|
? Ui::WhoReactedType::Forwarded
|
||||||
|
: repost
|
||||||
|
? Ui::WhoReactedType::Reposted
|
||||||
|
: Ui::WhoReactedType::Viewed;
|
||||||
|
const auto status = repost ? ComposeRepostStatus(date, *repost) : date;
|
||||||
const auto show = _controller->uiShow();
|
const auto show = _controller->uiShow();
|
||||||
const auto prepare = [&](Ui::PeerUserpicView &view) {
|
const auto prepare = [&](Ui::PeerUserpicView &view) {
|
||||||
const auto size = st::storiesWhoViewed.photoSize;
|
const auto size = st::storiesWhoViewed.photoSize;
|
||||||
|
@ -483,7 +511,8 @@ void RecentViews::addMenuRow(Data::StoryView entry, const QDateTime &now) {
|
||||||
userpic.setDevicePixelRatio(style::DevicePixelRatio());
|
userpic.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
return Ui::WhoReactedEntryData{
|
return Ui::WhoReactedEntryData{
|
||||||
.text = peer->name(),
|
.text = peer->name(),
|
||||||
.date = date,
|
.date = status,
|
||||||
|
.type = type,
|
||||||
.customEntityData = Data::ReactionEntityData(entry.reaction),
|
.customEntityData = Data::ReactionEntityData(entry.reaction),
|
||||||
.userpic = std::move(userpic),
|
.userpic = std::move(userpic),
|
||||||
.callback = [=] { show->show(PrepareShortInfoBox(peer)); },
|
.callback = [=] { show->show(PrepareShortInfoBox(peer)); },
|
||||||
|
@ -493,7 +522,8 @@ void RecentViews::addMenuRow(Data::StoryView entry, const QDateTime &now) {
|
||||||
const auto i = _menuEntries.end() - (_menuPlaceholderCount--);
|
const auto i = _menuEntries.end() - (_menuPlaceholderCount--);
|
||||||
auto data = prepare(i->view);
|
auto data = prepare(i->view);
|
||||||
i->peer = peer;
|
i->peer = peer;
|
||||||
i->date = date;
|
i->type = type;
|
||||||
|
i->status = status;
|
||||||
i->customEntityData = data.customEntityData;
|
i->customEntityData = data.customEntityData;
|
||||||
i->callback = data.callback;
|
i->callback = data.callback;
|
||||||
i->action->setData(std::move(data));
|
i->action->setData(std::move(data));
|
||||||
|
@ -512,7 +542,8 @@ void RecentViews::addMenuRow(Data::StoryView entry, const QDateTime &now) {
|
||||||
_menuEntries.push_back({
|
_menuEntries.push_back({
|
||||||
.action = raw,
|
.action = raw,
|
||||||
.peer = peer,
|
.peer = peer,
|
||||||
.date = date,
|
.type = type,
|
||||||
|
.status = status,
|
||||||
.customEntityData = std::move(customEntityData),
|
.customEntityData = std::move(customEntityData),
|
||||||
.callback = std::move(callback),
|
.callback = std::move(callback),
|
||||||
.view = std::move(view),
|
.view = std::move(view),
|
||||||
|
@ -533,7 +564,7 @@ void RecentViews::addMenuRowPlaceholder(not_null<Main::Session*> session) {
|
||||||
_menu->menu(),
|
_menu->menu(),
|
||||||
Data::ReactedMenuFactory(session),
|
Data::ReactedMenuFactory(session),
|
||||||
_menu->menu()->st(),
|
_menu->menu()->st(),
|
||||||
Ui::WhoReactedEntryData{ .preloader = true });
|
Ui::WhoReactedEntryData{ .type = Ui::WhoReactedType::Preloader });
|
||||||
const auto raw = action.get();
|
const auto raw = action.get();
|
||||||
_menu->addAction(std::move(action));
|
_menu->addAction(std::move(action));
|
||||||
_menuEntries.push_back({ .action = raw });
|
_menuEntries.push_back({ .action = raw });
|
||||||
|
@ -550,11 +581,15 @@ void RecentViews::rebuildMenuTail() {
|
||||||
const auto added = std::min(
|
const auto added = std::min(
|
||||||
_menuPlaceholderCount + kAddPerPage,
|
_menuPlaceholderCount + kAddPerPage,
|
||||||
int(views.list.size() - elements));
|
int(views.list.size() - elements));
|
||||||
|
const auto height = _menu->height();
|
||||||
for (auto i = elements, till = i + added; i != till; ++i) {
|
for (auto i = elements, till = i + added; i != till; ++i) {
|
||||||
const auto &entry = views.list[i];
|
const auto &entry = views.list[i];
|
||||||
addMenuRow(entry, now);
|
addMenuRow(entry, now);
|
||||||
}
|
}
|
||||||
_menuEntriesCount = _menuEntriesCount.current() + added;
|
_menuEntriesCount = _menuEntriesCount.current() + added;
|
||||||
|
if (const auto delta = _menu->height() - height) {
|
||||||
|
_menu->move(_menu->x(), _menu->y() - delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecentViews::subscribeToMenuUserpicsLoading(
|
void RecentViews::subscribeToMenuUserpicsLoading(
|
||||||
|
@ -590,7 +625,8 @@ void RecentViews::subscribeToMenuUserpicsLoading(
|
||||||
userpic.setDevicePixelRatio(style::DevicePixelRatio());
|
userpic.setDevicePixelRatio(style::DevicePixelRatio());
|
||||||
entry.action->setData({
|
entry.action->setData({
|
||||||
.text = peer->name(),
|
.text = peer->name(),
|
||||||
.date = entry.date,
|
.date = entry.status,
|
||||||
|
.type = entry.type,
|
||||||
.customEntityData = entry.customEntityData,
|
.customEntityData = entry.customEntityData,
|
||||||
.userpic = std::move(userpic),
|
.userpic = std::move(userpic),
|
||||||
.callback = entry.callback,
|
.callback = entry.callback,
|
||||||
|
|
|
@ -23,6 +23,7 @@ class RpWidget;
|
||||||
class GroupCallUserpics;
|
class GroupCallUserpics;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
class WhoReactedEntryAction;
|
class WhoReactedEntryAction;
|
||||||
|
enum class WhoReactedType : uchar;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
|
@ -43,6 +44,8 @@ enum class RecentViewsType {
|
||||||
struct RecentViewsData {
|
struct RecentViewsData {
|
||||||
std::vector<not_null<PeerData*>> list;
|
std::vector<not_null<PeerData*>> list;
|
||||||
int reactions = 0;
|
int reactions = 0;
|
||||||
|
int forwards = 0;
|
||||||
|
int views = 0;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
RecentViewsType type = RecentViewsType::Other;
|
RecentViewsType type = RecentViewsType::Other;
|
||||||
|
|
||||||
|
@ -72,7 +75,8 @@ private:
|
||||||
struct MenuEntry {
|
struct MenuEntry {
|
||||||
not_null<Ui::WhoReactedEntryAction*> action;
|
not_null<Ui::WhoReactedEntryAction*> action;
|
||||||
PeerData *peer = nullptr;
|
PeerData *peer = nullptr;
|
||||||
QString date;
|
Ui::WhoReactedType type = {};
|
||||||
|
QString status;
|
||||||
QString customEntityData;
|
QString customEntityData;
|
||||||
Fn<void()> callback;
|
Fn<void()> callback;
|
||||||
Ui::PeerUserpicView view;
|
Ui::PeerUserpicView view;
|
||||||
|
|
|
@ -5019,6 +5019,7 @@ void OverlayWidget::paintCaptionContent(
|
||||||
const auto inner = full.marginsRemoved(
|
const auto inner = full.marginsRemoved(
|
||||||
_stories ? _stories->repostCaptionPadding() : QMargins());
|
_stories ? _stories->repostCaptionPadding() : QMargins());
|
||||||
if (_stories) {
|
if (_stories) {
|
||||||
|
p.setOpacity(1.);
|
||||||
if (_stories->repost()) {
|
if (_stories->repost()) {
|
||||||
_stories->drawRepostInfo(p, full.x(), full.y(), full.width());
|
_stories->drawRepostInfo(p, full.x(), full.y(), full.width());
|
||||||
}
|
}
|
||||||
|
|
|
@ -791,6 +791,10 @@ whoReadDateChecks: icon{{ "menu/read_ticks_s", windowSubTextFg }};
|
||||||
whoReadDateChecksOver: icon{{ "menu/read_ticks_s", windowSubTextFgOver }};
|
whoReadDateChecksOver: icon{{ "menu/read_ticks_s", windowSubTextFgOver }};
|
||||||
whoLikedDateHeart: icon{{ "menu/read_react_s", windowSubTextFg }};
|
whoLikedDateHeart: icon{{ "menu/read_react_s", windowSubTextFg }};
|
||||||
whoLikedDateHeartOver: icon{{ "menu/read_react_s", windowSubTextFgOver }};
|
whoLikedDateHeartOver: icon{{ "menu/read_react_s", windowSubTextFgOver }};
|
||||||
|
whoRepostedDateHeart: icon{{ "mediaview/mini_repost", groupCallMemberActiveIcon, point(4px, 4px) }};
|
||||||
|
whoRepostedDateHeartOver: icon{{ "mediaview/mini_repost", groupCallMemberActiveIcon, point(4px, 4px) }};
|
||||||
|
whoForwardedDateHeart: icon{{ "statistics/mini_stats_share", groupCallMemberActiveIcon, point(4px, 4px) }};
|
||||||
|
whoForwardedDateHeartOver: icon{{ "statistics/mini_stats_share", groupCallMemberActiveIcon, point(4px, 4px) }};
|
||||||
whoReadDateChecksPosition: point(-7px, -4px);
|
whoReadDateChecksPosition: point(-7px, -4px);
|
||||||
whoReadDateStyle: TextStyle(defaultTextStyle) {
|
whoReadDateStyle: TextStyle(defaultTextStyle) {
|
||||||
font: font(12px);
|
font: font(12px);
|
||||||
|
|
|
@ -509,8 +509,7 @@ void WhoReactedEntryAction::setData(Data &&data) {
|
||||||
{ data.date },
|
{ data.date },
|
||||||
MenuTextOptions);
|
MenuTextOptions);
|
||||||
}
|
}
|
||||||
_dateReacted = data.dateReacted;
|
_type = data.type;
|
||||||
_preloader = data.preloader;
|
|
||||||
_custom = _customEmojiFactory
|
_custom = _customEmojiFactory
|
||||||
? _customEmojiFactory(data.customEntityData, [=] { update(); })
|
? _customEmojiFactory(data.customEntityData, [=] { update(); })
|
||||||
: nullptr;
|
: nullptr;
|
||||||
|
@ -545,13 +544,14 @@ void WhoReactedEntryAction::paint(Painter &&p) {
|
||||||
const auto photoSize = st::defaultWhoRead.photoSize;
|
const auto photoSize = st::defaultWhoRead.photoSize;
|
||||||
const auto photoLeft = st::defaultWhoRead.photoLeft;
|
const auto photoLeft = st::defaultWhoRead.photoLeft;
|
||||||
const auto photoTop = (height() - photoSize) / 2;
|
const auto photoTop = (height() - photoSize) / 2;
|
||||||
const auto preloaderBrush = _preloader
|
const auto preloader = (_type == WhoReactedType::Preloader);
|
||||||
|
const auto preloaderBrush = preloader
|
||||||
? [&] {
|
? [&] {
|
||||||
auto color = _st.itemFg->c;
|
auto color = _st.itemFg->c;
|
||||||
color.setAlphaF(color.alphaF() * kPreloaderAlpha);
|
color.setAlphaF(color.alphaF() * kPreloaderAlpha);
|
||||||
return QBrush(color);
|
return QBrush(color);
|
||||||
}() : QBrush();
|
}() : QBrush();
|
||||||
if (_preloader) {
|
if (preloader) {
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(preloaderBrush);
|
p.setBrush(preloaderBrush);
|
||||||
|
@ -568,7 +568,7 @@ void WhoReactedEntryAction::paint(Painter &&p) {
|
||||||
const auto textTop = withDate
|
const auto textTop = withDate
|
||||||
? st::whoReadNameWithDateTop
|
? st::whoReadNameWithDateTop
|
||||||
: (height() - _st.itemStyle.font->height) / 2;
|
: (height() - _st.itemStyle.font->height) / 2;
|
||||||
if (_preloader) {
|
if (_type == WhoReactedType::Preloader) {
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.setBrush(preloaderBrush);
|
p.setBrush(preloaderBrush);
|
||||||
|
@ -597,10 +597,28 @@ void WhoReactedEntryAction::paint(Painter &&p) {
|
||||||
const auto iconPosition = QPoint(
|
const auto iconPosition = QPoint(
|
||||||
st::defaultWhoRead.nameLeft,
|
st::defaultWhoRead.nameLeft,
|
||||||
st::whoReadDateTop) + st::whoReadDateChecksPosition;
|
st::whoReadDateTop) + st::whoReadDateChecksPosition;
|
||||||
const auto &icon = _dateReacted
|
const auto icon = [&] {
|
||||||
? (selected ? st::whoLikedDateHeartOver : st::whoLikedDateHeart)
|
switch (_type) {
|
||||||
: (selected ? st::whoReadDateChecksOver : st::whoReadDateChecks);
|
case WhoReactedType::Viewed:
|
||||||
icon.paint(p, iconPosition, width());
|
return &(selected
|
||||||
|
? st::whoReadDateChecksOver
|
||||||
|
: st::whoReadDateChecks);
|
||||||
|
case WhoReactedType::Reacted:
|
||||||
|
return &(selected
|
||||||
|
? st::whoLikedDateHeartOver
|
||||||
|
: st::whoLikedDateHeart);
|
||||||
|
case WhoReactedType::Reposted:
|
||||||
|
return &(selected
|
||||||
|
? st::whoRepostedDateHeartOver
|
||||||
|
: st::whoRepostedDateHeart);
|
||||||
|
case WhoReactedType::Forwarded:
|
||||||
|
return &(selected
|
||||||
|
? st::whoForwardedDateHeartOver
|
||||||
|
: st::whoForwardedDateHeart);
|
||||||
|
}
|
||||||
|
Unexpected("Type in WhoReactedEntryAction::paint.");
|
||||||
|
}();
|
||||||
|
icon->paint(p, iconPosition, width());
|
||||||
p.setPen(selected ? _st.itemFgShortcutOver : _st.itemFgShortcut);
|
p.setPen(selected ? _st.itemFgShortcutOver : _st.itemFgShortcut);
|
||||||
_date.drawLeftElided(
|
_date.drawLeftElided(
|
||||||
p,
|
p,
|
||||||
|
@ -708,7 +726,9 @@ void WhoReactedListMenu::populate(
|
||||||
append({
|
append({
|
||||||
.text = participant.name,
|
.text = participant.name,
|
||||||
.date = participant.date,
|
.date = participant.date,
|
||||||
.dateReacted = participant.dateReacted,
|
.type = (participant.dateReacted
|
||||||
|
? WhoReactedType::Reacted
|
||||||
|
: WhoReactedType::Viewed),
|
||||||
.customEntityData = participant.customEntityData,
|
.customEntityData = participant.customEntityData,
|
||||||
.userpic = participant.userpicLarge,
|
.userpic = participant.userpicLarge,
|
||||||
.callback = chosen,
|
.callback = chosen,
|
||||||
|
|
|
@ -54,11 +54,18 @@ struct WhoReadContent {
|
||||||
Fn<void(uint64)> participantChosen,
|
Fn<void(uint64)> participantChosen,
|
||||||
Fn<void()> showAllChosen);
|
Fn<void()> showAllChosen);
|
||||||
|
|
||||||
|
enum class WhoReactedType : uchar {
|
||||||
|
Viewed,
|
||||||
|
Reacted,
|
||||||
|
Reposted,
|
||||||
|
Forwarded,
|
||||||
|
Preloader,
|
||||||
|
};
|
||||||
|
|
||||||
struct WhoReactedEntryData {
|
struct WhoReactedEntryData {
|
||||||
QString text;
|
QString text;
|
||||||
QString date;
|
QString date;
|
||||||
bool dateReacted = false;
|
WhoReactedType type = WhoReactedType::Viewed;
|
||||||
bool preloader = false;
|
|
||||||
QString customEntityData;
|
QString customEntityData;
|
||||||
QImage userpic;
|
QImage userpic;
|
||||||
Fn<void()> callback;
|
Fn<void()> callback;
|
||||||
|
@ -95,8 +102,7 @@ private:
|
||||||
QImage _userpic;
|
QImage _userpic;
|
||||||
int _textWidth = 0;
|
int _textWidth = 0;
|
||||||
int _customSize = 0;
|
int _customSize = 0;
|
||||||
bool _dateReacted = false;
|
WhoReactedType _type = WhoReactedType::Viewed;
|
||||||
bool _preloader = false;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue