mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Top peers context menu.
This commit is contained in:
parent
56e28feb00
commit
19ae76d8de
8 changed files with 126 additions and 18 deletions
|
@ -56,6 +56,19 @@ rpl::producer<> TopPeers::updates() const {
|
||||||
return _updates.events();
|
return _updates.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TopPeers::remove(not_null<PeerData*> peer) {
|
||||||
|
const auto i = ranges::find(_list, peer, &TopPeer::peer);
|
||||||
|
if (i != end(_list)) {
|
||||||
|
_list.erase(i);
|
||||||
|
_updates.fire({});
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestId = _session->api().request(MTPcontacts_ResetTopPeerRating(
|
||||||
|
MTP_topPeerCategoryCorrespondents(),
|
||||||
|
peer->input
|
||||||
|
)).send();
|
||||||
|
}
|
||||||
|
|
||||||
void TopPeers::increment(not_null<PeerData*> peer, TimeId date) {
|
void TopPeers::increment(not_null<PeerData*> peer, TimeId date) {
|
||||||
if (date <= _lastReceivedDate) {
|
if (date <= _lastReceivedDate) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
[[nodiscard]] bool disabled() const;
|
[[nodiscard]] bool disabled() const;
|
||||||
[[nodiscard]] rpl::producer<> updates() const;
|
[[nodiscard]] rpl::producer<> updates() const;
|
||||||
|
|
||||||
|
void remove(not_null<PeerData*> peer);
|
||||||
void increment(not_null<PeerData*> peer, TimeId date);
|
void increment(not_null<PeerData*> peer, TimeId date);
|
||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
|
|
|
@ -1027,7 +1027,7 @@ void Widget::updateControlsVisibility(bool fast) {
|
||||||
_suggestions->show();
|
_suggestions->show();
|
||||||
}
|
}
|
||||||
updateStoriesVisibility();
|
updateStoriesVisibility();
|
||||||
if ((_openedFolder || _openedForum) && _searchHasFocus.current()) {
|
if ((_openedFolder || _openedForum) && _searchHasFocus) {
|
||||||
setInnerFocus();
|
setInnerFocus();
|
||||||
}
|
}
|
||||||
if (_updateTelegram) {
|
if (_updateTelegram) {
|
||||||
|
@ -1066,7 +1066,7 @@ void Widget::updateControlsVisibility(bool fast) {
|
||||||
if (_hideChildListCanvas) {
|
if (_hideChildListCanvas) {
|
||||||
_hideChildListCanvas->show();
|
_hideChildListCanvas->show();
|
||||||
}
|
}
|
||||||
if (_childList && _searchHasFocus.current()) {
|
if (_childList && _searchHasFocus) {
|
||||||
setInnerFocus();
|
setInnerFocus();
|
||||||
}
|
}
|
||||||
updateLockUnlockPosition();
|
updateLockUnlockPosition();
|
||||||
|
@ -1090,16 +1090,26 @@ void Widget::updateLockUnlockPosition() {
|
||||||
|
|
||||||
void Widget::updateHasFocus(not_null<QWidget*> focused) {
|
void Widget::updateHasFocus(not_null<QWidget*> focused) {
|
||||||
const auto has = (focused == _search.data());
|
const auto has = (focused == _search.data());
|
||||||
if (_searchHasFocus.current() != has) {
|
if (_searchHasFocus != has) {
|
||||||
_searchHasFocus = (focused == _search.data());
|
_searchHasFocus = has;
|
||||||
updateStoriesVisibility();
|
const auto update = [=] {
|
||||||
updateForceDisplayWide();
|
updateStoriesVisibility();
|
||||||
updateSuggestions(anim::type::normal);
|
updateForceDisplayWide();
|
||||||
|
updateSuggestions(anim::type::normal);
|
||||||
|
};
|
||||||
|
if (has) {
|
||||||
|
update();
|
||||||
|
} else {
|
||||||
|
// Search field may loose focus from the destructor of some
|
||||||
|
// widget, in that case we don't want to destroy _suggestions
|
||||||
|
// syncrhonously, because it may lead to a crash.
|
||||||
|
crl::on_main(this, update);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::updateSuggestions(anim::type animated) {
|
void Widget::updateSuggestions(anim::type animated) {
|
||||||
const auto suggest = _searchHasFocus.current()
|
const auto suggest = _searchHasFocus
|
||||||
&& !_searchInChat
|
&& !_searchInChat
|
||||||
&& (_inner->state() == WidgetState::Default);
|
&& (_inner->state() == WidgetState::Default);
|
||||||
if (!suggest && _suggestions) {
|
if (!suggest && _suggestions) {
|
||||||
|
@ -1108,6 +1118,7 @@ void Widget::updateSuggestions(anim::type animated) {
|
||||||
} else if (suggest && !_suggestions) {
|
} else if (suggest && !_suggestions) {
|
||||||
_suggestions = std::make_unique<Suggestions>(
|
_suggestions = std::make_unique<Suggestions>(
|
||||||
this,
|
this,
|
||||||
|
controller(),
|
||||||
TopPeersContent(&session()));
|
TopPeersContent(&session()));
|
||||||
|
|
||||||
_suggestions->topPeerChosen(
|
_suggestions->topPeerChosen(
|
||||||
|
@ -1563,7 +1574,7 @@ void Widget::updateStoriesVisibility() {
|
||||||
|| _openedForum
|
|| _openedForum
|
||||||
|| !_widthAnimationCache.isNull()
|
|| !_widthAnimationCache.isNull()
|
||||||
|| _childList
|
|| _childList
|
||||||
|| _searchHasFocus.current()
|
|| _searchHasFocus
|
||||||
|| !_search->getLastText().isEmpty()
|
|| !_search->getLastText().isEmpty()
|
||||||
|| _searchInChat
|
|| _searchInChat
|
||||||
|| _stories->empty();
|
|| _stories->empty();
|
||||||
|
@ -1681,7 +1692,7 @@ void Widget::slideFinished() {
|
||||||
_shownProgressValue = 1.;
|
_shownProgressValue = 1.;
|
||||||
updateControlsVisibility(true);
|
updateControlsVisibility(true);
|
||||||
if ((!_subsectionTopBar || !_subsectionTopBar->searchHasFocus())
|
if ((!_subsectionTopBar || !_subsectionTopBar->searchHasFocus())
|
||||||
&& !_searchHasFocus.current()) {
|
&& !_searchHasFocus) {
|
||||||
controller()->widget()->setInnerFocus();
|
controller()->widget()->setInnerFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2524,7 +2535,7 @@ void Widget::applySearchUpdate(bool force) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::updateForceDisplayWide() {
|
void Widget::updateForceDisplayWide() {
|
||||||
controller()->setChatsForceDisplayWide(_searchHasFocus.current()
|
controller()->setChatsForceDisplayWide(_searchHasFocus
|
||||||
|| !_search->getLastText().isEmpty()
|
|| !_search->getLastText().isEmpty()
|
||||||
|| _searchInChat);
|
|| _searchInChat);
|
||||||
}
|
}
|
||||||
|
@ -3258,7 +3269,7 @@ bool Widget::cancelSearch() {
|
||||||
_inner->clearFilter();
|
_inner->clearFilter();
|
||||||
clearSearchField();
|
clearSearchField();
|
||||||
applySearchUpdate();
|
applySearchUpdate();
|
||||||
if (!_searchInChat && _searchHasFocus.current()) {
|
if (!_searchInChat && _searchHasFocus) {
|
||||||
setFocus();
|
setFocus();
|
||||||
}
|
}
|
||||||
return clearingQuery || clearingInChat;
|
return clearingQuery || clearingInChat;
|
||||||
|
|
|
@ -300,7 +300,7 @@ private:
|
||||||
std::vector<Data::ReactionId> _searchTags;
|
std::vector<Data::ReactionId> _searchTags;
|
||||||
rpl::lifetime _searchTagsLifetime;
|
rpl::lifetime _searchTagsLifetime;
|
||||||
QString _lastSearchText;
|
QString _lastSearchText;
|
||||||
rpl::variable<bool> _searchHasFocus = false;
|
bool _searchHasFocus = false;
|
||||||
|
|
||||||
rpl::event_stream<rpl::producer<Stories::Content>> _storiesContents;
|
rpl::event_stream<rpl::producer<Stories::Content>> _storiesContents;
|
||||||
base::flat_map<PeerId, Ui::PeerUserpicView> _storiesUserpicsViewsHidden;
|
base::flat_map<PeerId, Ui::PeerUserpicView> _storiesUserpicsViewsHidden;
|
||||||
|
|
|
@ -22,13 +22,55 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/wrap/vertical_layout.h"
|
#include "ui/wrap/vertical_layout.h"
|
||||||
#include "ui/wrap/slide_wrap.h"
|
#include "ui/wrap/slide_wrap.h"
|
||||||
#include "ui/dynamic_thumbnails.h"
|
#include "ui/dynamic_thumbnails.h"
|
||||||
|
#include "window/window_session_controller.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
|
#include "styles/style_menu_icons.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void FillTopPeerMenu(
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
|
const ShowTopPeerMenuRequest &request,
|
||||||
|
Fn<void(not_null<PeerData*>)> remove) {
|
||||||
|
const auto owner = &controller->session().data();
|
||||||
|
const auto peer = owner->peer(PeerId(request.id));
|
||||||
|
const auto &add = request.callback;
|
||||||
|
const auto group = peer->isMegagroup();
|
||||||
|
const auto channel = peer->isChannel();
|
||||||
|
|
||||||
|
const auto showHistoryText = group
|
||||||
|
? tr::lng_context_open_group(tr::now)
|
||||||
|
: channel
|
||||||
|
? tr::lng_context_open_channel(tr::now)
|
||||||
|
: tr::lng_profile_send_message(tr::now);
|
||||||
|
add(showHistoryText, [=] {
|
||||||
|
controller->showPeerHistory(peer);
|
||||||
|
}, channel ? &st::menuIconChannel : &st::menuIconChatBubble);
|
||||||
|
|
||||||
|
const auto viewProfileText = group
|
||||||
|
? tr::lng_context_view_group(tr::now)
|
||||||
|
: channel
|
||||||
|
? tr::lng_context_view_channel(tr::now)
|
||||||
|
: tr::lng_context_view_profile(tr::now);
|
||||||
|
add(viewProfileText, [=] {
|
||||||
|
controller->showPeerInfo(peer);
|
||||||
|
}, channel ? &st::menuIconInfo : &st::menuIconProfile);
|
||||||
|
|
||||||
|
add({
|
||||||
|
.text = tr::lng_recent_remove(tr::now),
|
||||||
|
.handler = [=] { remove(peer); },
|
||||||
|
.icon = &st::menuIconDeleteAttention,
|
||||||
|
.isAttention = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Suggestions::Suggestions(
|
Suggestions::Suggestions(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
rpl::producer<TopPeersList> topPeers)
|
rpl::producer<TopPeersList> topPeers)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _scroll(std::make_unique<Ui::ElasticScroll>(this))
|
, _scroll(std::make_unique<Ui::ElasticScroll>(this))
|
||||||
|
@ -45,6 +87,15 @@ Suggestions::Suggestions(
|
||||||
_topPeers->clicks() | rpl::start_with_next([=](uint64 peerIdRaw) {
|
_topPeers->clicks() | rpl::start_with_next([=](uint64 peerIdRaw) {
|
||||||
_topPeerChosen.fire(PeerId(peerIdRaw));
|
_topPeerChosen.fire(PeerId(peerIdRaw));
|
||||||
}, _topPeers->lifetime());
|
}, _topPeers->lifetime());
|
||||||
|
|
||||||
|
_topPeers->showMenuRequests(
|
||||||
|
) | rpl::start_with_next([=](const ShowTopPeerMenuRequest &request) {
|
||||||
|
const auto remove = crl::guard(this, [=](not_null<PeerData*> peer) {
|
||||||
|
peer->session().topPeers().remove(peer);
|
||||||
|
_topPeers->removeLocally(peer->id.value);
|
||||||
|
});
|
||||||
|
FillTopPeerMenu(controller, request, remove);
|
||||||
|
}, _topPeers->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
Suggestions::~Suggestions() = default;
|
Suggestions::~Suggestions() = default;
|
||||||
|
@ -111,6 +162,9 @@ rpl::producer<TopPeersList> TopPeersContent(
|
||||||
const auto now = base::unixtime::now();
|
const auto now = base::unixtime::now();
|
||||||
for (const auto &peer : top) {
|
for (const auto &peer : top) {
|
||||||
const auto user = peer->asUser();
|
const auto user = peer->asUser();
|
||||||
|
if (user->isInaccessible()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const auto self = user && user->isSelf();
|
const auto self = user && user->isSelf();
|
||||||
const auto history = peer->owner().history(peer);
|
const auto history = peer->owner().history(peer);
|
||||||
const auto badges = history->chatListBadgesState();
|
const auto badges = history->chatListBadgesState();
|
||||||
|
|
|
@ -22,12 +22,17 @@ template <typename Widget>
|
||||||
class SlideWrap;
|
class SlideWrap;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
|
namespace Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
||||||
class Suggestions final : public Ui::RpWidget {
|
class Suggestions final : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
Suggestions(
|
Suggestions(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
|
not_null<Window::SessionController*> controller,
|
||||||
rpl::producer<TopPeersList> topPeers);
|
rpl::producer<TopPeersList> topPeers);
|
||||||
~Suggestions();
|
~Suggestions();
|
||||||
|
|
||||||
|
|
|
@ -212,13 +212,29 @@ auto TopPeersStrip::showMenuRequests() const
|
||||||
return _showMenuRequests.events();
|
return _showMenuRequests.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TopPeersStrip::removeLocally(uint64 id) {
|
||||||
|
_removed.emplace(id);
|
||||||
|
const auto i = ranges::find(_entries, id, &Entry::id);
|
||||||
|
if (i == end(_entries)) {
|
||||||
|
return;
|
||||||
|
} else if (i->subscribed) {
|
||||||
|
i->userpic->subscribeToUpdates(nullptr);
|
||||||
|
}
|
||||||
|
_entries.erase(i);
|
||||||
|
updateScrollMax();
|
||||||
|
if (_entries.empty()) {
|
||||||
|
_empty = true;
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void TopPeersStrip::apply(const TopPeersList &list) {
|
void TopPeersStrip::apply(const TopPeersList &list) {
|
||||||
auto now = std::vector<Entry>();
|
auto now = std::vector<Entry>();
|
||||||
|
|
||||||
if (list.entries.empty()) {
|
|
||||||
_empty = true;
|
|
||||||
}
|
|
||||||
for (const auto &entry : list.entries) {
|
for (const auto &entry : list.entries) {
|
||||||
|
if (_removed.contains(entry.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const auto i = ranges::find(_entries, entry.id, &Entry::id);
|
const auto i = ranges::find(_entries, entry.id, &Entry::id);
|
||||||
if (i != end(_entries)) {
|
if (i != end(_entries)) {
|
||||||
now.push_back(base::take(*i));
|
now.push_back(base::take(*i));
|
||||||
|
@ -227,6 +243,9 @@ void TopPeersStrip::apply(const TopPeersList &list) {
|
||||||
}
|
}
|
||||||
apply(now.back(), entry);
|
apply(now.back(), entry);
|
||||||
}
|
}
|
||||||
|
if (now.empty()) {
|
||||||
|
_empty = true;
|
||||||
|
}
|
||||||
for (auto &entry : _entries) {
|
for (auto &entry : _entries) {
|
||||||
if (entry.subscribed) {
|
if (entry.subscribed) {
|
||||||
entry.userpic->subscribeToUpdates(nullptr);
|
entry.userpic->subscribeToUpdates(nullptr);
|
||||||
|
@ -234,6 +253,7 @@ void TopPeersStrip::apply(const TopPeersList &list) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_entries = std::move(now);
|
_entries = std::move(now);
|
||||||
|
updateScrollMax();
|
||||||
unsubscribeUserpics();
|
unsubscribeUserpics();
|
||||||
if (!_entries.empty()) {
|
if (!_entries.empty()) {
|
||||||
_empty = false;
|
_empty = false;
|
||||||
|
@ -289,9 +309,10 @@ void TopPeersStrip::paintEvent(QPaintEvent *e) {
|
||||||
const auto single = st.photoLeft * 2 + st.photo;
|
const auto single = st.photoLeft * 2 + st.photo;
|
||||||
|
|
||||||
const auto from = std::min(_scrollLeft / single, int(_entries.size()));
|
const auto from = std::min(_scrollLeft / single, int(_entries.size()));
|
||||||
const auto till = std::max(
|
const auto till = std::clamp(
|
||||||
(_scrollLeft + width() + single - 1) / single + 1,
|
(_scrollLeft + width() + single - 1) / single + 1,
|
||||||
from);
|
from,
|
||||||
|
int(_entries.size()));
|
||||||
|
|
||||||
auto x = -_scrollLeft + from * single;
|
auto x = -_scrollLeft + from * single;
|
||||||
for (auto i = from; i != till; ++i) {
|
for (auto i = from; i != till; ++i) {
|
||||||
|
|
|
@ -49,6 +49,8 @@ public:
|
||||||
[[nodiscard]] auto showMenuRequests() const
|
[[nodiscard]] auto showMenuRequests() const
|
||||||
-> rpl::producer<ShowTopPeerMenuRequest>;
|
-> rpl::producer<ShowTopPeerMenuRequest>;
|
||||||
|
|
||||||
|
void removeLocally(uint64 id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Entry;
|
struct Entry;
|
||||||
|
|
||||||
|
@ -73,6 +75,7 @@ private:
|
||||||
|
|
||||||
std::vector<Entry> _entries;
|
std::vector<Entry> _entries;
|
||||||
rpl::variable<bool> _empty = true;
|
rpl::variable<bool> _empty = true;
|
||||||
|
base::flat_set<uint64> _removed;
|
||||||
|
|
||||||
rpl::event_stream<uint64> _clicks;
|
rpl::event_stream<uint64> _clicks;
|
||||||
rpl::event_stream<ShowTopPeerMenuRequest> _showMenuRequests;
|
rpl::event_stream<ShowTopPeerMenuRequest> _showMenuRequests;
|
||||||
|
|
Loading…
Add table
Reference in a new issue