mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-18 07:07:08 +02:00
Top peer realtime badges.
This commit is contained in:
parent
b259c566b7
commit
56e28feb00
7 changed files with 205 additions and 20 deletions
|
@ -1108,7 +1108,7 @@ void Widget::updateSuggestions(anim::type animated) {
|
|||
} else if (suggest && !_suggestions) {
|
||||
_suggestions = std::make_unique<Suggestions>(
|
||||
this,
|
||||
rpl::single(TopPeersContent(&session())));
|
||||
TopPeersContent(&session()));
|
||||
|
||||
_suggestions->topPeerChosen(
|
||||
) | rpl::start_with_next([=](PeerId id) {
|
||||
|
|
|
@ -7,8 +7,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#include "dialogs/ui/dialogs_suggestions.h"
|
||||
|
||||
#include "base/unixtime.h"
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "history/history.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/widgets/buttons.h"
|
||||
|
@ -82,17 +87,146 @@ object_ptr<Ui::RpWidget> Suggestions::setupDivider() {
|
|||
return result;
|
||||
}
|
||||
|
||||
TopPeersList TopPeersContent(not_null<Main::Session*> session) {
|
||||
auto base = TopPeersList();
|
||||
const auto top = session->topPeers().list();
|
||||
for (const auto &peer : top) {
|
||||
base.entries.push_back(TopPeersEntry{
|
||||
.id = peer->id.value,
|
||||
.name = peer->shortName(),
|
||||
.userpic = Ui::MakeUserpicThumbnail(peer),
|
||||
});
|
||||
}
|
||||
return base;
|
||||
rpl::producer<TopPeersList> TopPeersContent(
|
||||
not_null<Main::Session*> session) {
|
||||
return [=](auto consumer) {
|
||||
auto lifetime = rpl::lifetime();
|
||||
|
||||
struct Entry {
|
||||
not_null<History*> history;
|
||||
int index = 0;
|
||||
};
|
||||
struct State {
|
||||
TopPeersList data;
|
||||
base::flat_map<not_null<PeerData*>, Entry> indices;
|
||||
base::has_weak_ptr guard;
|
||||
bool scheduled = true;
|
||||
};
|
||||
auto state = lifetime.make_state<State>();
|
||||
const auto top = session->topPeers().list();
|
||||
auto &entries = state->data.entries;
|
||||
auto &indices = state->indices;
|
||||
entries.reserve(top.size());
|
||||
indices.reserve(top.size());
|
||||
const auto now = base::unixtime::now();
|
||||
for (const auto &peer : top) {
|
||||
const auto user = peer->asUser();
|
||||
const auto self = user && user->isSelf();
|
||||
const auto history = peer->owner().history(peer);
|
||||
const auto badges = history->chatListBadgesState();
|
||||
entries.push_back({
|
||||
.id = peer->id.value,
|
||||
.name = (self
|
||||
? tr::lng_saved_messages(tr::now)
|
||||
: peer->shortName()),
|
||||
.userpic = (self
|
||||
? Ui::MakeSavedMessagesThumbnail()
|
||||
: Ui::MakeUserpicThumbnail(peer)),
|
||||
.badge = uint32(badges.unreadCounter),
|
||||
.unread = badges.unread,
|
||||
.muted = !self && history->muted(),
|
||||
.online = user && !self && Data::IsUserOnline(user, now),
|
||||
});
|
||||
if (entries.back().online) {
|
||||
user->owner().watchForOffline(user, now);
|
||||
}
|
||||
indices.emplace(peer, Entry{
|
||||
.history = peer->owner().history(peer),
|
||||
.index = int(entries.size()) - 1,
|
||||
});
|
||||
}
|
||||
|
||||
const auto push = [=] {
|
||||
if (!state->scheduled) {
|
||||
return;
|
||||
}
|
||||
state->scheduled = false;
|
||||
consumer.put_next_copy(state->data);
|
||||
};
|
||||
const auto schedule = [=] {
|
||||
if (state->scheduled) {
|
||||
return;
|
||||
}
|
||||
state->scheduled = true;
|
||||
crl::on_main(&state->guard, push);
|
||||
};
|
||||
|
||||
using Flag = Data::PeerUpdate::Flag;
|
||||
session->changes().peerUpdates(
|
||||
Flag::Name
|
||||
| Flag::Photo
|
||||
| Flag::Notifications
|
||||
| Flag::OnlineStatus
|
||||
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
||||
const auto peer = update.peer;
|
||||
if (peer->isSelf()) {
|
||||
return;
|
||||
}
|
||||
const auto i = state->indices.find(peer);
|
||||
if (i == end(state->indices)) {
|
||||
return;
|
||||
}
|
||||
auto changed = false;
|
||||
auto &entry = state->data.entries[i->second.index];
|
||||
const auto flags = update.flags;
|
||||
if (flags & Flag::Name) {
|
||||
const auto now = peer->shortName();
|
||||
if (entry.name != now) {
|
||||
entry.name = now;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (flags & Flag::Photo) {
|
||||
entry.userpic = Ui::MakeUserpicThumbnail(peer);
|
||||
changed = true;
|
||||
}
|
||||
if (flags & Flag::Notifications) {
|
||||
const auto now = i->second.history->muted();
|
||||
if (entry.muted != now) {
|
||||
entry.muted = now;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (flags & Flag::OnlineStatus) {
|
||||
if (const auto user = peer->asUser()) {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto value = Data::IsUserOnline(user, now);
|
||||
if (entry.online != value) {
|
||||
entry.online = value;
|
||||
changed = true;
|
||||
if (value) {
|
||||
user->owner().watchForOffline(user, now);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
schedule();
|
||||
}
|
||||
}, lifetime);
|
||||
|
||||
session->data().unreadBadgeChanges(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto changed = false;
|
||||
auto &entries = state->data.entries;
|
||||
for (const auto &[peer, data] : state->indices) {
|
||||
const auto badges = data.history->chatListBadgesState();
|
||||
auto &entry = entries[data.index];
|
||||
if (entry.badge != badges.unreadCounter
|
||||
|| entry.unread != badges.unread) {
|
||||
entry.badge = badges.unreadCounter;
|
||||
entry.unread = badges.unread;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
schedule();
|
||||
}
|
||||
}, lifetime);
|
||||
|
||||
push();
|
||||
return lifetime;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Dialogs
|
||||
|
|
|
@ -53,7 +53,7 @@ private:
|
|||
|
||||
};
|
||||
|
||||
[[nodiscard]] TopPeersList TopPeersContent(
|
||||
[[nodiscard]] rpl::producer<TopPeersList> TopPeersContent(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
} // namespace Dialogs
|
||||
|
|
|
@ -445,7 +445,7 @@ void TopPeersStrip::updateSelected() {
|
|||
const auto p = mapFromGlobal(_lastMousePosition);
|
||||
const auto x = p.x();
|
||||
const auto single = st.photoLeft * 2 + st.photo;
|
||||
const auto index = (x - _scrollLeft) / single;
|
||||
const auto index = (_scrollLeft + x) / single;
|
||||
const auto selected = (index < 0 || index >= _entries.size())
|
||||
? -1
|
||||
: index;
|
||||
|
|
|
@ -22,6 +22,7 @@ struct TopPeersEntry {
|
|||
QString name;
|
||||
std::shared_ptr<Ui::DynamicImage> userpic;
|
||||
uint32 badge : 28 = 0;
|
||||
uint32 unread : 1 = 0;
|
||||
uint32 muted : 1 = 0;
|
||||
uint32 online : 1 = 0;
|
||||
};
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_photo_media.h"
|
||||
#include "data/data_story.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/empty_userpic.h"
|
||||
#include "ui/dynamic_image.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/userpic_view.h"
|
||||
|
@ -39,6 +40,7 @@ private:
|
|||
Ui::PeerUserpicView view;
|
||||
Fn<void()> callback;
|
||||
InMemoryKey key;
|
||||
int paletteVersion = 0;
|
||||
rpl::lifetime photoLifetime;
|
||||
rpl::lifetime downloadLifetime;
|
||||
};
|
||||
|
@ -117,6 +119,17 @@ private:
|
|||
|
||||
};
|
||||
|
||||
class SavedMessagesUserpic final : public DynamicImage {
|
||||
public:
|
||||
QImage image(int size) override;
|
||||
void subscribeToUpdates(Fn<void()> callback) override;
|
||||
|
||||
private:
|
||||
QImage _frame;
|
||||
int _paletteVersion = 0;
|
||||
|
||||
};
|
||||
|
||||
PeerUserpic::PeerUserpic(not_null<PeerData*> peer, bool forceRound)
|
||||
: _peer(peer)
|
||||
, _forceRound(forceRound) {
|
||||
|
@ -127,13 +140,21 @@ QImage PeerUserpic::image(int size) {
|
|||
|
||||
const auto good = (_frame.width() == size * _frame.devicePixelRatio());
|
||||
const auto key = _peer->userpicUniqueKey(_subscribed->view);
|
||||
if (!good || (_subscribed->key != key && !waitingUserpicLoad())) {
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
const auto paletteVersion = style::PaletteVersion();
|
||||
if (!good
|
||||
|| (_subscribed->paletteVersion != paletteVersion
|
||||
&& _peer->useEmptyUserpic(_subscribed->view))
|
||||
|| (_subscribed->key != key && !waitingUserpicLoad())) {
|
||||
_subscribed->key = key;
|
||||
_frame = QImage(
|
||||
QSize(size, size) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
_subscribed->paletteVersion = paletteVersion;
|
||||
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
if (!good) {
|
||||
_frame = QImage(
|
||||
QSize(size, size) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
}
|
||||
_frame.fill(Qt::transparent);
|
||||
|
||||
auto p = Painter(&_frame);
|
||||
|
@ -313,6 +334,30 @@ QImage EmptyThumbnail::image(int size) {
|
|||
void EmptyThumbnail::subscribeToUpdates(Fn<void()> callback) {
|
||||
}
|
||||
|
||||
QImage SavedMessagesUserpic::image(int size) {
|
||||
const auto good = (_frame.width() == size * _frame.devicePixelRatio());
|
||||
const auto paletteVersion = style::PaletteVersion();
|
||||
if (!good || _paletteVersion != paletteVersion) {
|
||||
_paletteVersion = paletteVersion;
|
||||
|
||||
const auto ratio = style::DevicePixelRatio();
|
||||
if (!good) {
|
||||
_frame = QImage(
|
||||
QSize(size, size) * ratio,
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
_frame.setDevicePixelRatio(ratio);
|
||||
}
|
||||
_frame.fill(Qt::transparent);
|
||||
|
||||
auto p = Painter(&_frame);
|
||||
Ui::EmptyUserpic::PaintSavedMessages(p, 0, 0, size, size);
|
||||
}
|
||||
return _frame;
|
||||
}
|
||||
|
||||
void SavedMessagesUserpic::subscribeToUpdates(Fn<void()> callback) {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<DynamicImage> MakeUserpicThumbnail(
|
||||
|
@ -321,6 +366,10 @@ std::shared_ptr<DynamicImage> MakeUserpicThumbnail(
|
|||
return std::make_shared<PeerUserpic>(peer, forceRound);
|
||||
}
|
||||
|
||||
std::shared_ptr<DynamicImage> MakeSavedMessagesThumbnail() {
|
||||
return std::make_shared<SavedMessagesUserpic>();
|
||||
}
|
||||
|
||||
std::shared_ptr<DynamicImage> MakeStoryThumbnail(
|
||||
not_null<Data::Story*> story) {
|
||||
using Result = std::shared_ptr<DynamicImage>;
|
||||
|
|
|
@ -20,6 +20,7 @@ class DynamicImage;
|
|||
[[nodiscard]] std::shared_ptr<DynamicImage> MakeUserpicThumbnail(
|
||||
not_null<PeerData*> peer,
|
||||
bool forceRound = false);
|
||||
[[nodiscard]] std::shared_ptr<DynamicImage> MakeSavedMessagesThumbnail();
|
||||
[[nodiscard]] std::shared_ptr<DynamicImage> MakeStoryThumbnail(
|
||||
not_null<Data::Story*> story);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue