mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Initial version of top peers.
This commit is contained in:
parent
11e4c45969
commit
18598f8dca
21 changed files with 908 additions and 27 deletions
|
@ -460,10 +460,14 @@ PRIVATE
|
|||
data/business/data_business_info.h
|
||||
data/business/data_shortcut_messages.cpp
|
||||
data/business/data_shortcut_messages.h
|
||||
data/components/recent_peers.cpp
|
||||
data/components/recent_peers.h
|
||||
data/components/scheduled_messages.cpp
|
||||
data/components/scheduled_messages.h
|
||||
data/components/sponsored_messages.cpp
|
||||
data/components/sponsored_messages.h
|
||||
data/components/top_peers.cpp
|
||||
data/components/top_peers.h
|
||||
data/notify/data_notify_settings.cpp
|
||||
data/notify/data_notify_settings.h
|
||||
data/notify/data_peer_notify_settings.cpp
|
||||
|
@ -608,6 +612,18 @@ PRIVATE
|
|||
data/data_wall_paper.h
|
||||
data/data_web_page.cpp
|
||||
data/data_web_page.h
|
||||
dialogs/ui/dialogs_layout.cpp
|
||||
dialogs/ui/dialogs_layout.h
|
||||
dialogs/ui/dialogs_message_view.cpp
|
||||
dialogs/ui/dialogs_message_view.h
|
||||
dialogs/ui/dialogs_stories_content.cpp
|
||||
dialogs/ui/dialogs_stories_content.h
|
||||
dialogs/ui/dialogs_suggestions.cpp
|
||||
dialogs/ui/dialogs_suggestions.h
|
||||
dialogs/ui/dialogs_topics_view.cpp
|
||||
dialogs/ui/dialogs_topics_view.h
|
||||
dialogs/ui/dialogs_video_userpic.cpp
|
||||
dialogs/ui/dialogs_video_userpic.h
|
||||
dialogs/dialogs_entry.cpp
|
||||
dialogs/dialogs_entry.h
|
||||
dialogs/dialogs_indexed_list.cpp
|
||||
|
@ -630,16 +646,6 @@ PRIVATE
|
|||
dialogs/dialogs_search_tags.h
|
||||
dialogs/dialogs_widget.cpp
|
||||
dialogs/dialogs_widget.h
|
||||
dialogs/ui/dialogs_layout.cpp
|
||||
dialogs/ui/dialogs_layout.h
|
||||
dialogs/ui/dialogs_message_view.cpp
|
||||
dialogs/ui/dialogs_message_view.h
|
||||
dialogs/ui/dialogs_stories_content.cpp
|
||||
dialogs/ui/dialogs_stories_content.h
|
||||
dialogs/ui/dialogs_topics_view.cpp
|
||||
dialogs/ui/dialogs_topics_view.h
|
||||
dialogs/ui/dialogs_video_userpic.cpp
|
||||
dialogs/ui/dialogs_video_userpic.h
|
||||
editor/color_picker.cpp
|
||||
editor/color_picker.h
|
||||
editor/controllers/controllers.h
|
||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "mtproto/mtproto_dc_options.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_saved_messages.h"
|
||||
|
@ -1577,6 +1578,11 @@ void Updates::feedUpdate(const MTPUpdate &update) {
|
|||
} else {
|
||||
if (existing) {
|
||||
existing->destroy();
|
||||
} else {
|
||||
// Not the server-side date, but close enough.
|
||||
session().topPeers().increment(
|
||||
local->history()->peer,
|
||||
local->date());
|
||||
}
|
||||
local->setRealId(d.vid().v);
|
||||
}
|
||||
|
|
18
Telegram/SourceFiles/data/components/recent_peers.cpp
Normal file
18
Telegram/SourceFiles/data/components/recent_peers.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/components/recent_peers.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
RecentPeers::RecentPeers(not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
}
|
||||
|
||||
RecentPeers::~RecentPeers() = default;
|
||||
|
||||
} // namespace Data
|
26
Telegram/SourceFiles/data/components/recent_peers.h
Normal file
26
Telegram/SourceFiles/data/components/recent_peers.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
|
||||
class RecentPeers final {
|
||||
public:
|
||||
explicit RecentPeers(not_null<Main::Session*> session);
|
||||
~RecentPeers();
|
||||
|
||||
private:
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
157
Telegram/SourceFiles/data/components/top_peers.cpp
Normal file
157
Telegram/SourceFiles/data/components/top_peers.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "data/components/top_peers.h"
|
||||
|
||||
#include "api/api_hash.h"
|
||||
#include "apiwrap.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
|
||||
namespace Data {
|
||||
namespace {
|
||||
|
||||
constexpr auto kLimit = 32;
|
||||
constexpr auto kRequestTimeLimit = 10 * crl::time(1000);
|
||||
|
||||
[[nodiscard]] float64 RatingDelta(TimeId now, TimeId was, int decay) {
|
||||
return std::exp((now - was) * 1. / decay);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TopPeers::TopPeers(not_null<Main::Session*> session)
|
||||
: _session(session) {
|
||||
using namespace rpl::mappers;
|
||||
crl::on_main(session, [=] {
|
||||
_session->data().chatsListLoadedEvents(
|
||||
) | rpl::filter(_1 == nullptr) | rpl::start_with_next([=] {
|
||||
crl::on_main(_session, [=] {
|
||||
request();
|
||||
});
|
||||
}, _session->lifetime());
|
||||
});
|
||||
}
|
||||
|
||||
TopPeers::~TopPeers() = default;
|
||||
|
||||
std::vector<not_null<PeerData*>> TopPeers::list() const {
|
||||
return _list
|
||||
| ranges::view::transform(&TopPeer::peer)
|
||||
| ranges::to_vector;
|
||||
}
|
||||
|
||||
bool TopPeers::disabled() const {
|
||||
return _disabled;
|
||||
}
|
||||
|
||||
rpl::producer<> TopPeers::updates() const {
|
||||
return _updates.events();
|
||||
}
|
||||
|
||||
void TopPeers::increment(not_null<PeerData*> peer, TimeId date) {
|
||||
if (date <= _lastReceivedDate) {
|
||||
return;
|
||||
}
|
||||
if (const auto user = peer->asUser(); user && !user->isBot()) {
|
||||
auto changed = false;
|
||||
auto i = ranges::find(_list, peer, &TopPeer::peer);
|
||||
if (i == end(_list)) {
|
||||
_list.push_back({ .peer = peer });
|
||||
i = end(_list) - 1;
|
||||
changed = true;
|
||||
}
|
||||
const auto &config = peer->session().mtp().config();
|
||||
const auto decay = config.values().ratingDecay;
|
||||
i->rating += RatingDelta(date, _lastReceivedDate, decay);
|
||||
for (; i != begin(_list); --i) {
|
||||
if (i->rating >= (i - 1)->rating) {
|
||||
changed = true;
|
||||
std::swap(*i, *(i - 1));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
_updates.fire({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TopPeers::reload() {
|
||||
if (_requestId
|
||||
|| (_lastReceived
|
||||
&& _lastReceived + kRequestTimeLimit > crl::now())) {
|
||||
return;
|
||||
}
|
||||
request();
|
||||
}
|
||||
|
||||
void TopPeers::request() {
|
||||
if (_requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
_requestId = _session->api().request(MTPcontacts_GetTopPeers(
|
||||
MTP_flags(MTPcontacts_GetTopPeers::Flag::f_correspondents),
|
||||
MTP_int(0),
|
||||
MTP_int(kLimit),
|
||||
MTP_long(countHash())
|
||||
)).done([=](const MTPcontacts_TopPeers &result, const MTP::Response &response) {
|
||||
_lastReceivedDate = TimeId(response.outerMsgId >> 32);
|
||||
_lastReceived = crl::now();
|
||||
_requestId = 0;
|
||||
|
||||
result.match([&](const MTPDcontacts_topPeers &data) {
|
||||
_disabled = false;
|
||||
const auto owner = &_session->data();
|
||||
owner->processUsers(data.vusers());
|
||||
owner->processChats(data.vchats());
|
||||
for (const auto &category : data.vcategories().v) {
|
||||
const auto &data = category.data();
|
||||
data.vcategory().match(
|
||||
[&](const MTPDtopPeerCategoryCorrespondents &) {
|
||||
_list = ranges::views::all(
|
||||
data.vpeers().v
|
||||
) | ranges::views::transform([&](const MTPTopPeer &top) {
|
||||
return TopPeer{
|
||||
owner->peer(peerFromMTP(top.data().vpeer())),
|
||||
top.data().vrating().v,
|
||||
};
|
||||
}) | ranges::to_vector;
|
||||
}, [](const auto &) {
|
||||
LOG(("API Error: Unexpected top peer category."));
|
||||
});
|
||||
}
|
||||
_updates.fire({});
|
||||
}, [&](const MTPDcontacts_topPeersDisabled &) {
|
||||
if (!_disabled) {
|
||||
_list.clear();
|
||||
_disabled = true;
|
||||
_updates.fire({});
|
||||
}
|
||||
}, [](const MTPDcontacts_topPeersNotModified &) {
|
||||
});
|
||||
}).fail([=] {
|
||||
_lastReceived = crl::now();
|
||||
_requestId = 0;
|
||||
}).send();
|
||||
}
|
||||
|
||||
uint64 TopPeers::countHash() const {
|
||||
using namespace Api;
|
||||
auto hash = HashInit();
|
||||
for (const auto &top : _list) {
|
||||
HashUpdate(hash, peerToUser(top.peer->id).bare);
|
||||
}
|
||||
return HashFinalize(hash);
|
||||
}
|
||||
|
||||
} // namespace Data
|
51
Telegram/SourceFiles/data/components/top_peers.h
Normal file
51
Telegram/SourceFiles/data/components/top_peers.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Data {
|
||||
|
||||
class TopPeers final {
|
||||
public:
|
||||
explicit TopPeers(not_null<Main::Session*> session);
|
||||
~TopPeers();
|
||||
|
||||
[[nodiscard]] std::vector<not_null<PeerData*>> list() const;
|
||||
[[nodiscard]] bool disabled() const;
|
||||
[[nodiscard]] rpl::producer<> updates() const;
|
||||
|
||||
void increment(not_null<PeerData*> peer, TimeId date);
|
||||
void reload();
|
||||
|
||||
private:
|
||||
struct TopPeer {
|
||||
not_null<PeerData*> peer;
|
||||
float64 rating = 0.;
|
||||
};
|
||||
|
||||
void request();
|
||||
[[nodiscard]] uint64 countHash() const;
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
std::vector<TopPeer> _list;
|
||||
rpl::event_stream<> _updates;
|
||||
crl::time _lastReceived = 0;
|
||||
TimeId _lastReceivedDate = 0;
|
||||
|
||||
mtpRequestId _requestId = 0;
|
||||
|
||||
bool _disabled = false;
|
||||
bool _received = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Data
|
|
@ -591,6 +591,11 @@ dialogsStoriesFull: DialogsStories {
|
|||
font: font(11px);
|
||||
}
|
||||
}
|
||||
topPeers: DialogsStories(dialogsStoriesFull) {
|
||||
photo: 46px;
|
||||
photoLeft: 10px;
|
||||
photoTop: 8px;
|
||||
}
|
||||
|
||||
dialogsStoriesList: DialogsStoriesList {
|
||||
small: dialogsStories;
|
||||
|
@ -633,3 +638,4 @@ dialogsSearchTagArrowPadding: margins(-6px, 3px, 0px, 0px);
|
|||
dialogsSearchTagPromoLeft: 6px;
|
||||
dialogsSearchTagPromoRight: 1px;
|
||||
dialogsSearchTagPromoSkip: 6px;
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/options.h"
|
||||
#include "dialogs/ui/dialogs_stories_content.h"
|
||||
#include "dialogs/ui/dialogs_stories_list.h"
|
||||
#include "dialogs/ui/dialogs_suggestions.h"
|
||||
#include "dialogs/dialogs_inner_widget.h"
|
||||
#include "dialogs/dialogs_search_from_controllers.h"
|
||||
#include "dialogs/dialogs_key.h"
|
||||
|
@ -1021,7 +1022,10 @@ void Widget::fullSearchRefreshOn(rpl::producer<> events) {
|
|||
|
||||
void Widget::updateControlsVisibility(bool fast) {
|
||||
updateLoadMoreChatsVisibility();
|
||||
_scroll->show();
|
||||
_scroll->setVisible(!_suggestions);
|
||||
if (_suggestions) {
|
||||
_suggestions->show();
|
||||
}
|
||||
updateStoriesVisibility();
|
||||
if ((_openedFolder || _openedForum) && _searchHasFocus.current()) {
|
||||
setInnerFocus();
|
||||
|
@ -1085,8 +1089,36 @@ void Widget::updateLockUnlockPosition() {
|
|||
}
|
||||
|
||||
void Widget::updateHasFocus(not_null<QWidget*> focused) {
|
||||
_searchHasFocus = (focused == _search.data());
|
||||
updateForceDisplayWide();
|
||||
const auto has = (focused == _search.data());
|
||||
if (_searchHasFocus.current() != has) {
|
||||
_searchHasFocus = (focused == _search.data());
|
||||
updateStoriesVisibility();
|
||||
updateForceDisplayWide();
|
||||
updateSuggestions(anim::type::normal);
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::updateSuggestions(anim::type animated) {
|
||||
const auto suggest = _searchHasFocus.current()
|
||||
&& !_searchInChat
|
||||
&& (_inner->state() == WidgetState::Default);
|
||||
if (!suggest && _suggestions) {
|
||||
_suggestions = nullptr;
|
||||
_scroll->show();
|
||||
} else if (suggest && !_suggestions) {
|
||||
_suggestions = std::make_unique<Suggestions>(
|
||||
this,
|
||||
rpl::single(TopPeersContent(&session())));
|
||||
|
||||
_suggestions->topPeerChosen(
|
||||
) | rpl::start_with_next([=](PeerId id) {
|
||||
controller()->showPeerHistory(id);
|
||||
}, _suggestions->lifetime());
|
||||
|
||||
_suggestions->show();
|
||||
_scroll->hide();
|
||||
updateControlsGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::changeOpenedSubsection(
|
||||
|
@ -1513,7 +1545,10 @@ void Widget::startWidthAnimation() {
|
|||
void Widget::stopWidthAnimation() {
|
||||
_widthAnimationCache = QPixmap();
|
||||
if (!_showAnimation) {
|
||||
_scroll->show();
|
||||
_scroll->setVisible(!_suggestions);
|
||||
if (_suggestions) {
|
||||
_suggestions->show();
|
||||
}
|
||||
}
|
||||
updateStoriesVisibility();
|
||||
update();
|
||||
|
@ -1528,6 +1563,7 @@ void Widget::updateStoriesVisibility() {
|
|||
|| _openedForum
|
||||
|| !_widthAnimationCache.isNull()
|
||||
|| _childList
|
||||
|| _searchHasFocus.current()
|
||||
|| !_search->getLastText().isEmpty()
|
||||
|| _searchInChat
|
||||
|| _stories->empty();
|
||||
|
@ -2460,6 +2496,7 @@ void Widget::applySearchUpdate(bool force) {
|
|||
clearSearchCache();
|
||||
}
|
||||
_cancelSearch->toggle(!filterText.isEmpty(), anim::type::normal);
|
||||
updateSuggestions(anim::type::instant);
|
||||
updateLoadMoreChatsVisibility();
|
||||
updateJumpToDateVisibility();
|
||||
updateLockUnlockPosition();
|
||||
|
@ -2675,6 +2712,7 @@ bool Widget::setSearchInChat(
|
|||
if (searchInPeerUpdated) {
|
||||
_searchInChat = chat;
|
||||
controller()->setSearchInChat(_searchInChat);
|
||||
updateSuggestions(anim::type::instant);
|
||||
updateJumpToDateVisibility();
|
||||
updateStoriesVisibility();
|
||||
}
|
||||
|
@ -3041,6 +3079,14 @@ void Widget::updateControlsGeometry() {
|
|||
};
|
||||
_updateScrollGeometryCached();
|
||||
|
||||
if (_suggestions) {
|
||||
_suggestions->setGeometry(
|
||||
0,
|
||||
expandedStoriesTop,
|
||||
scrollWidth,
|
||||
height() - expandedStoriesTop - bottomSkip);
|
||||
}
|
||||
|
||||
_inner->resize(scrollWidth, _inner->height());
|
||||
_inner->setNarrowRatio(narrowRatio);
|
||||
if (newScrollTop != wasScrollTop) {
|
||||
|
@ -3097,6 +3143,7 @@ void Widget::keyPressEvent(QKeyEvent *e) {
|
|||
&& !_openedFolder
|
||||
&& !_openedForum
|
||||
&& _search->isVisible()
|
||||
&& !_search->hasFocus()
|
||||
&& !e->text().isEmpty()) {
|
||||
_search->setFocusFast();
|
||||
QCoreApplication::sendEvent(_search->rawTextEdit(), e);
|
||||
|
|
|
@ -75,6 +75,7 @@ class Key;
|
|||
struct ChosenRow;
|
||||
class InnerWidget;
|
||||
enum class SearchRequestType;
|
||||
class Suggestions;
|
||||
|
||||
class Widget final : public Window::AbstractSectionWidget {
|
||||
public:
|
||||
|
@ -242,6 +243,7 @@ private:
|
|||
void startScrollUpButtonAnimation(bool shown);
|
||||
void updateScrollUpPosition();
|
||||
void updateLockUnlockPosition();
|
||||
void updateSuggestions(anim::type animated);
|
||||
|
||||
MTP::Sender _api;
|
||||
|
||||
|
@ -273,6 +275,7 @@ private:
|
|||
|
||||
object_ptr<Ui::ElasticScroll> _scroll;
|
||||
QPointer<InnerWidget> _inner;
|
||||
std::unique_ptr<Suggestions> _suggestions;
|
||||
class BottomButton;
|
||||
object_ptr<BottomButton> _updateTelegram = { nullptr };
|
||||
object_ptr<BottomButton> _loadMoreChats = { nullptr };
|
||||
|
@ -291,7 +294,7 @@ private:
|
|||
|
||||
Data::Folder *_openedFolder = nullptr;
|
||||
Data::Forum *_openedForum = nullptr;
|
||||
Dialogs::Key _searchInChat;
|
||||
Key _searchInChat;
|
||||
History *_searchInMigrated = nullptr;
|
||||
PeerData *_searchFromAuthor = nullptr;
|
||||
std::vector<Data::ReactionId> _searchTags;
|
||||
|
|
|
@ -184,9 +184,9 @@ rpl::producer<bool> List::toggleExpandedRequests() const {
|
|||
return _toggleExpandedRequests.events();
|
||||
}
|
||||
|
||||
rpl::producer<> List::entered() const {
|
||||
return _entered.events();
|
||||
}
|
||||
//rpl::producer<> List::entered() const {
|
||||
// return _entered.events();
|
||||
//}
|
||||
|
||||
rpl::producer<> List::loadMoreRequests() const {
|
||||
return _loadMoreRequests.events();
|
||||
|
@ -217,9 +217,9 @@ void List::requestExpanded(bool expanded) {
|
|||
_toggleExpandedRequests.fire_copy(_expanded);
|
||||
}
|
||||
|
||||
void List::enterEventHook(QEnterEvent *e) {
|
||||
_entered.fire({});
|
||||
}
|
||||
//void List::enterEventHook(QEnterEvent *e) {
|
||||
//_entered.fire({});
|
||||
//}
|
||||
|
||||
void List::resizeEvent(QResizeEvent *e) {
|
||||
updateScrollMax();
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
[[nodiscard]] rpl::producer<uint64> clicks() const;
|
||||
[[nodiscard]] rpl::producer<ShowMenuRequest> showMenuRequests() const;
|
||||
[[nodiscard]] rpl::producer<bool> toggleExpandedRequests() const;
|
||||
[[nodiscard]] rpl::producer<> entered() const;
|
||||
//[[nodiscard]] rpl::producer<> entered() const;
|
||||
[[nodiscard]] rpl::producer<> loadMoreRequests() const;
|
||||
|
||||
[[nodiscard]] auto verticalScrollEvents() const
|
||||
|
@ -123,7 +123,7 @@ private:
|
|||
};
|
||||
|
||||
void showContent(Content &&content);
|
||||
void enterEventHook(QEnterEvent *e) override;
|
||||
//void enterEventHook(QEnterEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
|
@ -173,7 +173,7 @@ private:
|
|||
rpl::event_stream<uint64> _clicks;
|
||||
rpl::event_stream<ShowMenuRequest> _showMenuRequests;
|
||||
rpl::event_stream<bool> _toggleExpandedRequests;
|
||||
rpl::event_stream<> _entered;
|
||||
//rpl::event_stream<> _entered;
|
||||
rpl::event_stream<> _loadMoreRequests;
|
||||
rpl::event_stream<> _collapsedGeometryChanged;
|
||||
|
||||
|
|
77
Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp
Normal file
77
Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "dialogs/ui/dialogs_suggestions.h"
|
||||
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/data_user.h"
|
||||
#include "main/main_session.h"
|
||||
#include "ui/widgets/elastic_scroll.h"
|
||||
#include "ui/widgets/labels.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "ui/wrap/slide_wrap.h"
|
||||
#include "ui/dynamic_thumbnails.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
Suggestions::Suggestions(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<TopPeersList> topPeers)
|
||||
: RpWidget(parent)
|
||||
, _scroll(std::make_unique<Ui::ElasticScroll>(this))
|
||||
, _content(_scroll->setOwnedWidget(object_ptr<Ui::VerticalLayout>(this)))
|
||||
, _topPeersWrap(_content->add(object_ptr<Ui::SlideWrap<TopPeersStrip>>(
|
||||
this,
|
||||
object_ptr<TopPeersStrip>(this, std::move(topPeers)))))
|
||||
, _topPeers(_topPeersWrap->entity())
|
||||
, _divider(_content->add(setupDivider())) {
|
||||
_topPeers->emptyValue() | rpl::start_with_next([=](bool empty) {
|
||||
_topPeersWrap->toggle(!empty, anim::type::instant);
|
||||
}, _topPeers->lifetime());
|
||||
|
||||
_topPeers->clicks() | rpl::start_with_next([=](uint64 peerIdRaw) {
|
||||
_topPeerChosen.fire(PeerId(peerIdRaw));
|
||||
}, _topPeers->lifetime());
|
||||
}
|
||||
|
||||
Suggestions::~Suggestions() = default;
|
||||
|
||||
void Suggestions::paintEvent(QPaintEvent *e) {
|
||||
QPainter(this).fillRect(e->rect(), st::windowBg);
|
||||
}
|
||||
|
||||
void Suggestions::resizeEvent(QResizeEvent *e) {
|
||||
_scroll->setGeometry(rect());
|
||||
_content->resizeToWidth(width());
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> Suggestions::setupDivider() {
|
||||
auto result = object_ptr<Ui::DividerLabel>(
|
||||
this,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
this,
|
||||
rpl::single(u"Recent"_q),
|
||||
st::boxDividerLabel),
|
||||
st::defaultBoxDividerLabelPadding);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
TopPeersList TopPeersContent(not_null<Main::Session*> session) {
|
||||
auto result = TopPeersList();
|
||||
for (const auto &peer : session->topPeers().list()) {
|
||||
result.entries.push_back(TopPeersEntry{
|
||||
.id = peer->id.value,
|
||||
.name = peer->shortName(),
|
||||
.userpic = Ui::MakeUserpicThumbnail(peer),
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Dialogs
|
59
Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h
Normal file
59
Telegram/SourceFiles/dialogs/ui/dialogs_suggestions.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/object_ptr.h"
|
||||
#include "dialogs/ui/top_peers_strip.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class ElasticScroll;
|
||||
class VerticalLayout;
|
||||
template <typename Widget>
|
||||
class SlideWrap;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
class Suggestions final : public Ui::RpWidget {
|
||||
public:
|
||||
Suggestions(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<TopPeersList> topPeers);
|
||||
~Suggestions();
|
||||
|
||||
[[nodiscard]] rpl::producer<PeerId> topPeerChosen() const {
|
||||
return _topPeerChosen.events();
|
||||
}
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> setupDivider();
|
||||
|
||||
void updateControlsGeometry();
|
||||
|
||||
const std::unique_ptr<Ui::ElasticScroll> _scroll;
|
||||
const not_null<Ui::VerticalLayout*> _content;
|
||||
const not_null<Ui::SlideWrap<TopPeersStrip>*> _topPeersWrap;
|
||||
const not_null<TopPeersStrip*> _topPeers;
|
||||
const not_null<Ui::RpWidget*> _divider;
|
||||
|
||||
rpl::event_stream<PeerId> _topPeerChosen;
|
||||
|
||||
};
|
||||
|
||||
[[nodiscard]] TopPeersList TopPeersContent(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
} // namespace Dialogs
|
302
Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp
Normal file
302
Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp
Normal file
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#include "dialogs/ui/top_peers_strip.h"
|
||||
|
||||
#include "ui/text/text.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback_factory.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "ui/dynamic_image.h"
|
||||
#include "ui/painter.h"
|
||||
#include "styles/style_dialogs.h"
|
||||
#include "styles/style_widgets.h"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
struct TopPeersStrip::Entry {
|
||||
uint64 id = 0;
|
||||
Ui::Text::String name;
|
||||
std::shared_ptr<Ui::DynamicImage> userpic;
|
||||
bool subscribed = false;
|
||||
};
|
||||
|
||||
TopPeersStrip::TopPeersStrip(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<TopPeersList> content)
|
||||
: RpWidget(parent) {
|
||||
resize(0, st::topPeers.height);
|
||||
|
||||
std::move(content) | rpl::start_with_next([=](const TopPeersList &list) {
|
||||
apply(list);
|
||||
}, lifetime());
|
||||
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
TopPeersStrip::~TopPeersStrip() = default;
|
||||
|
||||
void TopPeersStrip::resizeEvent(QResizeEvent *e) {
|
||||
updateScrollMax();
|
||||
}
|
||||
|
||||
void TopPeersStrip::wheelEvent(QWheelEvent *e) {
|
||||
const auto phase = e->phase();
|
||||
const auto fullDelta = e->pixelDelta().isNull()
|
||||
? e->angleDelta()
|
||||
: e->pixelDelta();
|
||||
if (phase == Qt::ScrollBegin || phase == Qt::ScrollEnd) {
|
||||
_scrollingLock = Qt::Orientation();
|
||||
if (fullDelta.isNull()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
const auto vertical = qAbs(fullDelta.x()) < qAbs(fullDelta.y());
|
||||
if (_scrollingLock == Qt::Orientation() && phase != Qt::NoScrollPhase) {
|
||||
_scrollingLock = vertical ? Qt::Vertical : Qt::Horizontal;
|
||||
}
|
||||
if (_scrollingLock == Qt::Vertical || (vertical && !_scrollLeftMax)) {
|
||||
_verticalScrollEvents.fire(e);
|
||||
return;
|
||||
}
|
||||
const auto delta = vertical
|
||||
? fullDelta.y()
|
||||
: ((style::RightToLeft() ? -1 : 1) * fullDelta.x());
|
||||
|
||||
const auto now = _scrollLeft;
|
||||
const auto used = now - delta;
|
||||
const auto next = std::clamp(used, 0, _scrollLeftMax);
|
||||
if (next != now) {
|
||||
_scrollLeft = next;
|
||||
updateSelected();
|
||||
update();
|
||||
}
|
||||
e->accept();
|
||||
}
|
||||
|
||||
void TopPeersStrip::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
_lastMousePosition = e->globalPos();
|
||||
updateSelected();
|
||||
|
||||
_mouseDownPosition = _lastMousePosition;
|
||||
_pressed = _selected;
|
||||
}
|
||||
|
||||
void TopPeersStrip::mouseMoveEvent(QMouseEvent *e) {
|
||||
_lastMousePosition = e->globalPos();
|
||||
updateSelected();
|
||||
|
||||
if (!_dragging && _mouseDownPosition) {
|
||||
if ((_lastMousePosition - *_mouseDownPosition).manhattanLength()
|
||||
>= QApplication::startDragDistance()) {
|
||||
_dragging = true;
|
||||
_startDraggingLeft = _scrollLeft;
|
||||
}
|
||||
}
|
||||
checkDragging();
|
||||
}
|
||||
|
||||
void TopPeersStrip::checkDragging() {
|
||||
if (_dragging) {
|
||||
const auto sign = (style::RightToLeft() ? -1 : 1);
|
||||
const auto newLeft = std::clamp(
|
||||
(sign * (_mouseDownPosition->x() - _lastMousePosition.x())
|
||||
+ _startDraggingLeft),
|
||||
0,
|
||||
_scrollLeftMax);
|
||||
if (newLeft != _scrollLeft) {
|
||||
_scrollLeft = newLeft;
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TopPeersStrip::mouseReleaseEvent(QMouseEvent *e) {
|
||||
_lastMousePosition = e->globalPos();
|
||||
const auto guard = gsl::finally([&] {
|
||||
_mouseDownPosition = std::nullopt;
|
||||
});
|
||||
|
||||
const auto pressed = std::exchange(_pressed, -1);
|
||||
if (finishDragging()) {
|
||||
return;
|
||||
}
|
||||
updateSelected();
|
||||
if (_selected == pressed) {
|
||||
if (_selected < _entries.size()) {
|
||||
_clicks.fire_copy(_entries[_selected].id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TopPeersStrip::updateScrollMax() {
|
||||
const auto &st = st::topPeers;
|
||||
const auto single = st.photoLeft * 2 + st.photo;
|
||||
const auto widthFull = int(_entries.size()) * single;
|
||||
_scrollLeftMax = std::max(widthFull - width(), 0);
|
||||
_scrollLeft = std::clamp(_scrollLeft, 0, _scrollLeftMax);
|
||||
update();
|
||||
}
|
||||
|
||||
bool TopPeersStrip::empty() const {
|
||||
return _empty.current();
|
||||
}
|
||||
|
||||
rpl::producer<bool> TopPeersStrip::emptyValue() const {
|
||||
return _empty.value();
|
||||
}
|
||||
|
||||
rpl::producer<uint64> TopPeersStrip::clicks() const {
|
||||
return _clicks.events();
|
||||
}
|
||||
|
||||
auto TopPeersStrip::showMenuRequests() const
|
||||
-> rpl::producer<ShowTopPeerMenuRequest> {
|
||||
return _showMenuRequests.events();
|
||||
}
|
||||
|
||||
void TopPeersStrip::apply(const TopPeersList &list) {
|
||||
auto now = std::vector<Entry>();
|
||||
|
||||
if (list.entries.empty()) {
|
||||
_empty = true;
|
||||
}
|
||||
for (const auto &entry : list.entries) {
|
||||
const auto i = ranges::find(_entries, entry.id, &Entry::id);
|
||||
if (i != end(_entries)) {
|
||||
now.push_back(base::take(*i));
|
||||
} else {
|
||||
now.push_back({ .id = entry.id });
|
||||
}
|
||||
apply(now.back(), entry);
|
||||
}
|
||||
for (auto &entry : _entries) {
|
||||
if (entry.subscribed) {
|
||||
entry.userpic->subscribeToUpdates(nullptr);
|
||||
entry.subscribed = 0;
|
||||
}
|
||||
}
|
||||
_entries = std::move(now);
|
||||
if (!_entries.empty()) {
|
||||
_empty = false;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void TopPeersStrip::apply(Entry &entry, const TopPeersEntry &data) {
|
||||
Expects(entry.id == data.id);
|
||||
Expects(data.userpic != nullptr);
|
||||
|
||||
if (entry.name.toString() != data.name) {
|
||||
entry.name.setText(st::topPeers.nameStyle, data.name);
|
||||
}
|
||||
if (entry.userpic.get() != data.userpic.get()) {
|
||||
if (entry.subscribed) {
|
||||
entry.userpic->subscribeToUpdates(nullptr);
|
||||
entry.subscribed = 0;
|
||||
}
|
||||
entry.userpic = data.userpic;
|
||||
}
|
||||
}
|
||||
|
||||
void TopPeersStrip::paintEvent(QPaintEvent *e) {
|
||||
auto p = Painter(this);
|
||||
auto x = -_scrollLeft;
|
||||
const auto &st = st::topPeers;
|
||||
const auto line = st.lineTwice / 2;
|
||||
const auto single = st.photoLeft * 2 + st.photo;
|
||||
for (auto &entry : _entries) {
|
||||
if (!entry.subscribed) {
|
||||
entry.userpic->subscribeToUpdates([=] {
|
||||
update();
|
||||
});
|
||||
entry.subscribed = 1;
|
||||
}
|
||||
const auto image = entry.userpic->image(st.photo);
|
||||
p.drawImage(
|
||||
QRect(x + st.photoLeft, st.photoTop, st.photo, st.photo),
|
||||
image);
|
||||
|
||||
const auto nameLeft = x + st.nameLeft;
|
||||
entry.name.drawElided(p, nameLeft, st.nameTop, single, 1, style::al_top);
|
||||
|
||||
x += single;
|
||||
}
|
||||
}
|
||||
|
||||
void TopPeersStrip::contextMenuEvent(QContextMenuEvent *e) {
|
||||
_menu = nullptr;
|
||||
|
||||
if (e->reason() == QContextMenuEvent::Mouse) {
|
||||
_lastMousePosition = e->globalPos();
|
||||
updateSelected();
|
||||
}
|
||||
if (_selected < 0 || _entries.empty()) {
|
||||
return;
|
||||
}
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
this,
|
||||
st::popupMenuWithIcons);
|
||||
_showMenuRequests.fire({
|
||||
_entries[_selected].id,
|
||||
Ui::Menu::CreateAddActionCallback(_menu),
|
||||
});
|
||||
if (_menu->empty()) {
|
||||
_menu = nullptr;
|
||||
return;
|
||||
}
|
||||
const auto updateAfterMenuDestroyed = [=] {
|
||||
const auto globalPosition = QCursor::pos();
|
||||
if (rect().contains(mapFromGlobal(globalPosition))) {
|
||||
_lastMousePosition = globalPosition;
|
||||
updateSelected();
|
||||
}
|
||||
};
|
||||
QObject::connect(
|
||||
_menu.get(),
|
||||
&QObject::destroyed,
|
||||
crl::guard(&_menuGuard, updateAfterMenuDestroyed));
|
||||
_menu->popup(e->globalPos());
|
||||
e->accept();
|
||||
}
|
||||
|
||||
bool TopPeersStrip::finishDragging() {
|
||||
if (!_dragging) {
|
||||
return false;
|
||||
}
|
||||
checkDragging();
|
||||
_dragging = false;
|
||||
updateSelected();
|
||||
return true;
|
||||
}
|
||||
|
||||
void TopPeersStrip::updateSelected() {
|
||||
if (_pressed >= 0) {
|
||||
return;
|
||||
}
|
||||
const auto &st = st::topPeers;
|
||||
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 selected = (index < 0 || index >= _entries.size())
|
||||
? -1
|
||||
: index;
|
||||
if (_selected != selected) {
|
||||
const auto over = (selected >= 0);
|
||||
if (over != (_selected >= 0)) {
|
||||
setCursor(over ? style::cur_pointer : style::cur_default);
|
||||
}
|
||||
_selected = selected;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Dialogs
|
93
Telegram/SourceFiles/dialogs/ui/top_peers_strip.h
Normal file
93
Telegram/SourceFiles/dialogs/ui/top_peers_strip.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "base/weak_ptr.h"
|
||||
#include "ui/widgets/menu/menu_add_action_callback.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Ui {
|
||||
class DynamicImage;
|
||||
} // namespace Ui
|
||||
|
||||
namespace Dialogs {
|
||||
|
||||
struct TopPeersEntry {
|
||||
uint64 id = 0;
|
||||
QString name;
|
||||
std::shared_ptr<Ui::DynamicImage> userpic;
|
||||
uint32 badge : 30 = 0;
|
||||
uint32 muted : 1 = 0;
|
||||
uint32 online : 1 = 0;
|
||||
};
|
||||
|
||||
struct TopPeersList {
|
||||
std::vector<TopPeersEntry> entries;
|
||||
};
|
||||
|
||||
struct ShowTopPeerMenuRequest {
|
||||
uint64 id = 0;
|
||||
Ui::Menu::MenuCallback callback;
|
||||
};
|
||||
|
||||
class TopPeersStrip final : public Ui::RpWidget {
|
||||
public:
|
||||
TopPeersStrip(
|
||||
not_null<QWidget*> parent,
|
||||
rpl::producer<TopPeersList> content);
|
||||
~TopPeersStrip();
|
||||
|
||||
[[nodiscard]] bool empty() const;
|
||||
[[nodiscard]] rpl::producer<bool> emptyValue() const;
|
||||
[[nodiscard]] rpl::producer<uint64> clicks() const;
|
||||
[[nodiscard]] auto showMenuRequests() const
|
||||
-> rpl::producer<ShowTopPeerMenuRequest>;
|
||||
|
||||
private:
|
||||
struct Entry;
|
||||
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void wheelEvent(QWheelEvent *e) override;
|
||||
void mousePressEvent(QMouseEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
void contextMenuEvent(QContextMenuEvent *e) override;
|
||||
|
||||
void updateScrollMax();
|
||||
void updateSelected();
|
||||
void checkDragging();
|
||||
bool finishDragging();
|
||||
|
||||
void apply(const TopPeersList &list);
|
||||
void apply(Entry &entry, const TopPeersEntry &data);
|
||||
|
||||
std::vector<Entry> _entries;
|
||||
rpl::variable<bool> _empty = true;
|
||||
|
||||
rpl::event_stream<uint64> _clicks;
|
||||
rpl::event_stream<ShowTopPeerMenuRequest> _showMenuRequests;
|
||||
rpl::event_stream<not_null<QWheelEvent*>> _verticalScrollEvents;
|
||||
|
||||
QPoint _lastMousePosition;
|
||||
std::optional<QPoint> _mouseDownPosition;
|
||||
int _startDraggingLeft = 0;
|
||||
int _scrollLeft = 0;
|
||||
int _scrollLeftMax = 0;
|
||||
bool _dragging = false;
|
||||
Qt::Orientation _scrollingLock = {};
|
||||
|
||||
int _selected = -1;
|
||||
int _pressed = -1;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
base::has_weak_ptr _menuGuard;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Dialogs
|
|
@ -21,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/components/sponsored_messages.h"
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/notify/data_notify_settings.h"
|
||||
#include "data/stickers/data_stickers.h"
|
||||
#include "data/data_drafts.h"
|
||||
|
@ -429,9 +430,13 @@ not_null<HistoryItem*> History::createItem(
|
|||
}
|
||||
return result;
|
||||
}
|
||||
return message.match([&](const auto &data) {
|
||||
const auto result = message.match([&](const auto &data) {
|
||||
return makeMessage(id, data, localFlags);
|
||||
});
|
||||
if (result->out() && result->isRegular()) {
|
||||
session().topPeers().increment(peer, result->date());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<not_null<HistoryItem*>> History::createItems(
|
||||
|
|
|
@ -28,8 +28,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/file_upload.h"
|
||||
#include "storage/storage_account.h"
|
||||
#include "storage/storage_facade.h"
|
||||
#include "data/components/recent_peers.h"
|
||||
#include "data/components/scheduled_messages.h"
|
||||
#include "data/components/sponsored_messages.h"
|
||||
#include "data/components/top_peers.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_user.h"
|
||||
|
@ -100,6 +102,7 @@ Session::Session(
|
|||
, _attachWebView(std::make_unique<InlineBots::AttachWebView>(this))
|
||||
, _scheduledMessages(std::make_unique<Data::ScheduledMessages>(this))
|
||||
, _sponsoredMessages(std::make_unique<Data::SponsoredMessages>(this))
|
||||
, _topPeers(std::make_unique<Data::TopPeers>(this))
|
||||
, _supportHelper(Support::Helper::Create(this))
|
||||
, _saveSettingsTimer([=] { saveSettings(); }) {
|
||||
Expects(_settings != nullptr);
|
||||
|
|
|
@ -31,8 +31,10 @@ class Templates;
|
|||
namespace Data {
|
||||
class Session;
|
||||
class Changes;
|
||||
class RecentPeers;
|
||||
class ScheduledMessages;
|
||||
class SponsoredMessages;
|
||||
class TopPeers;
|
||||
} // namespace Data
|
||||
|
||||
namespace Storage {
|
||||
|
@ -106,12 +108,18 @@ public:
|
|||
[[nodiscard]] Data::Changes &changes() const {
|
||||
return *_changes;
|
||||
}
|
||||
[[nodiscard]] Data::RecentPeers &recentPeers() const {
|
||||
return *_recentPeers;
|
||||
}
|
||||
[[nodiscard]] Data::SponsoredMessages &sponsoredMessages() const {
|
||||
return *_sponsoredMessages;
|
||||
}
|
||||
[[nodiscard]] Data::ScheduledMessages &scheduledMessages() const {
|
||||
return *_scheduledMessages;
|
||||
}
|
||||
[[nodiscard]] Data::TopPeers &topPeers() const {
|
||||
return *_topPeers;
|
||||
}
|
||||
[[nodiscard]] Api::Updates &updates() const {
|
||||
return *_updates;
|
||||
}
|
||||
|
@ -232,8 +240,10 @@ private:
|
|||
const std::unique_ptr<Stickers::GiftBoxPack> _giftBoxStickersPacks;
|
||||
const std::unique_ptr<SendAsPeers> _sendAsPeers;
|
||||
const std::unique_ptr<InlineBots::AttachWebView> _attachWebView;
|
||||
const std::unique_ptr<Data::RecentPeers> _recentPeers;
|
||||
const std::unique_ptr<Data::ScheduledMessages> _scheduledMessages;
|
||||
const std::unique_ptr<Data::SponsoredMessages> _sponsoredMessages;
|
||||
const std::unique_ptr<Data::TopPeers> _topPeers;
|
||||
|
||||
const std::unique_ptr<Support::Helper> _supportHelper;
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@ QByteArray Config::serialize() const {
|
|||
+ Serialize::stringSize(_fields.txtDomainString)
|
||||
+ 3 * sizeof(qint32)
|
||||
+ Serialize::stringSize(_fields.reactionDefaultEmoji)
|
||||
+ sizeof(quint64);
|
||||
+ sizeof(quint64)
|
||||
+ sizeof(qint32);
|
||||
|
||||
auto result = QByteArray();
|
||||
result.reserve(size);
|
||||
|
@ -89,7 +90,8 @@ QByteArray Config::serialize() const {
|
|||
<< qint32(_fields.blockedMode ? 1 : 0)
|
||||
<< qint32(_fields.captionLengthMax)
|
||||
<< _fields.reactionDefaultEmoji
|
||||
<< quint64(_fields.reactionDefaultCustom);
|
||||
<< quint64(_fields.reactionDefaultCustom)
|
||||
<< qint32(_fields.ratingDecay);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -185,6 +187,9 @@ std::unique_ptr<Config> Config::FromSerialized(const QByteArray &serialized) {
|
|||
read(raw->_fields.reactionDefaultEmoji);
|
||||
read(raw->_fields.reactionDefaultCustom);
|
||||
}
|
||||
if (!stream.atEnd()) {
|
||||
read(raw->_fields.ratingDecay);
|
||||
}
|
||||
|
||||
if (stream.status() != QDataStream::Ok
|
||||
|| !raw->_dcOptions.constructFromSerialized(dcOptionsSerialized)) {
|
||||
|
@ -249,6 +254,10 @@ void Config::apply(const MTPDconfig &data) {
|
|||
});
|
||||
}
|
||||
_fields.autologinToken = qs(data.vautologin_token().value_or_empty());
|
||||
_fields.ratingDecay = data.vrating_e_decay().v;
|
||||
if (_fields.ratingDecay <= 0) {
|
||||
_fields.ratingDecay = ConfigFields().ratingDecay;
|
||||
}
|
||||
|
||||
if (data.vdc_options().v.empty()) {
|
||||
LOG(("MTP Error: config with empty dc_options received!"));
|
||||
|
|
|
@ -39,6 +39,7 @@ struct ConfigFields {
|
|||
QString txtDomainString;
|
||||
bool blockedMode = false;
|
||||
int captionLengthMax = 1024;
|
||||
int ratingDecay = 2419200;
|
||||
QString reactionDefaultEmoji = ConfigDefaultReactionEmoji();
|
||||
uint64 reactionDefaultCustom;
|
||||
QString autologinToken;
|
||||
|
|
|
@ -87,6 +87,8 @@ PRIVATE
|
|||
dialogs/dialogs_three_state_icon.h
|
||||
dialogs/ui/dialogs_stories_list.cpp
|
||||
dialogs/ui/dialogs_stories_list.h
|
||||
dialogs/ui/top_peers_strip.cpp
|
||||
dialogs/ui/top_peers_strip.h
|
||||
|
||||
editor/controllers/undo_controller.cpp
|
||||
editor/controllers/undo_controller.h
|
||||
|
|
Loading…
Add table
Reference in a new issue