Show hidden stories above contacts list.

This commit is contained in:
John Preston 2023-06-02 21:14:15 +04:00
parent f40391b4f0
commit e7c0385aea
9 changed files with 130 additions and 22 deletions

View File

@ -3789,6 +3789,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_userpic_builder_color_subtitle" = "Choose background";
"lng_userpic_builder_emoji_subtitle" = "Choose sticker or emoji";
"lng_stories_hide_to_contacts" = "Archive";
"lng_stories_show_in_chats" = "Unarchive";
"lng_stories_row_count#one" = "{count} Story";
"lng_stories_row_count#other" = "{count} Stories";
"lng_stories_row_unread_and_one" = "{accumulated}, {user}";

View File

@ -37,6 +37,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_profile.h"
#include "styles/style_dialogs.h"
#include "data/data_stories.h"
#include "dialogs/ui/dialogs_stories_content.h"
#include "dialogs/ui/dialogs_stories_list.h"
namespace {
constexpr auto kSortByOnlineThrottle = 3 * crl::time(1000);
@ -51,10 +56,14 @@ object_ptr<Ui::BoxContent> PrepareContactsBox(
&sessionController->session());
const auto raw = controller.get();
auto init = [=](not_null<PeerListBox*> box) {
using namespace Dialogs;
struct State {
QPointer<Ui::IconButton> toggleSort;
Stories::List *stories = nullptr;
QPointer<::Ui::IconButton> toggleSort;
Mode mode = ContactsBoxController::SortMode::Online;
};
const auto state = box->lifetime().make_state<State>();
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
box->addLeftButton(
@ -69,6 +78,43 @@ object_ptr<Ui::BoxContent> PrepareContactsBox(
online ? &st::contactsSortOnlineIconOver : nullptr);
});
raw->setSortMode(Mode::Online);
auto stories = object_ptr<Stories::List>(
box,
Stories::ContentForSession(
&sessionController->session(),
Data::StorySourcesList::All),
[=] { return state->stories->height() - box->scrollTop(); });
const auto raw = state->stories = stories.data();
box->peerListSetAboveWidget(std::move(stories));
raw->entered(
) | rpl::start_with_next([=] {
//clearSelection();
}, raw->lifetime());
raw->clicks(
) | rpl::start_with_next([=](uint64 id) {
sessionController->openPeerStories(PeerId(int64(id)), {});
}, raw->lifetime());
raw->showProfileRequests(
) | rpl::start_with_next([=](uint64 id) {
sessionController->showPeerInfo(PeerId(int64(id)));
}, raw->lifetime());
raw->toggleShown(
) | rpl::start_with_next([=](Stories::ToggleShownRequest request) {
sessionController->session().data().stories().toggleHidden(
PeerId(int64(request.id)),
!request.shown);
}, raw->lifetime());
raw->loadMoreRequests(
) | rpl::start_with_next([=] {
sessionController->session().data().stories().loadMore(
Data::StorySourcesList::All);
}, raw->lifetime());
};
return Box<PeerListBox>(std::move(controller), std::move(init));
}

View File

@ -350,9 +350,11 @@ void Stories::parseAndApply(const MTPUserStories &stories) {
const auto peerId = peerFromUser(data.vuser_id());
const auto readTill = data.vmax_read_id().value_or_empty();
const auto count = int(data.vstories().v.size());
const auto user = _owner->peer(peerId)->asUser();
auto result = StoriesSource{
.user = _owner->peer(peerId)->asUser(),
.user = user,
.readTill = readTill,
.hidden = user->hasStoriesHidden(),
};
const auto &list = data.vstories().v;
result.ids.reserve(list.size());
@ -806,6 +808,58 @@ void Stories::markAsRead(FullStoryId id, bool viewed) {
_markReadTimer.callOnce(kMarkAsReadDelay);
}
void Stories::toggleHidden(PeerId peerId, bool hidden) {
const auto user = _owner->peer(peerId)->asUser();
Assert(user != nullptr);
if (user->hasStoriesHidden() != hidden) {
user->setFlags(hidden
? (user->flags() | UserDataFlag::StoriesHidden)
: (user->flags() & ~UserDataFlag::StoriesHidden));
session().api().request(MTPcontacts_ToggleStoriesHidden(
user->inputUser,
MTP_bool(hidden)
)).send();
}
const auto i = _all.find(peerId);
if (i == end(_all)) {
return;
}
i->second.hidden = hidden;
const auto main = static_cast<int>(StorySourcesList::NotHidden);
const auto all = static_cast<int>(StorySourcesList::All);
if (hidden) {
const auto i = ranges::find(
_sources[main],
peerId,
&StoriesSourceInfo::id);
if (i != end(_sources[main])) {
_sources[main].erase(i);
_sourcesChanged[main].fire({});
}
const auto j = ranges::find(_sources[all], peerId, &StoriesSourceInfo::id);
if (j != end(_sources[all])) {
j->hidden = hidden;
_sourcesChanged[all].fire({});
}
} else {
const auto i = ranges::find(
_sources[all],
peerId,
&StoriesSourceInfo::id);
if (i != end(_sources[all])) {
i->hidden = hidden;
_sourcesChanged[all].fire({});
auto &sources = _sources[main];
if (!ranges::contains(sources, peerId, &StoriesSourceInfo::id)) {
sources.push_back(*i);
sort(StorySourcesList::NotHidden);
}
}
}
}
void Stories::sendMarkAsReadRequest(
not_null<PeerData*> peer,
StoryId tillId) {

View File

@ -176,6 +176,8 @@ public:
[[nodiscard]] bool isQuitPrevent();
void markAsRead(FullStoryId id, bool viewed);
void toggleHidden(PeerId peerId, bool hidden);
static constexpr auto kViewsPerPage = 50;
void loadViewsSlice(
StoryId id,

View File

@ -351,18 +351,9 @@ InnerWidget::InnerWidget(
_stories->toggleShown(
) | rpl::start_with_next([=](Stories::ToggleShownRequest request) {
const auto peerId = PeerId(int64(request.id));
const auto user = session().data().peer(peerId)->asUser();
Assert(user != nullptr);
if (user->hasStoriesHidden() == request.shown) {
user->setFlags(request.shown
? (user->flags() & ~UserDataFlag::StoriesHidden)
: (user->flags() | UserDataFlag::StoriesHidden));
session().api().request(MTPcontacts_ToggleStoriesHidden(
user->inputUser,
MTP_bool(!request.shown)
)).send();
}
session().data().stories().toggleHidden(
PeerId(int64(request.id)),
!request.shown);
}, lifetime());
_stories->loadMoreRequests(

View File

@ -149,6 +149,7 @@ Content State::next() {
.name = user->shortName(),
.userpic = std::move(userpic),
.unread = info.unread,
.hidden = info.hidden,
});
}
return result;

View File

@ -99,6 +99,7 @@ void List::showContent(Content &&content) {
item.nameCache = QImage();
}
item.user.unread = user.unread;
item.user.hidden = user.hidden;
} else {
_data.items.emplace_back(Item{ .user = user });
}
@ -429,8 +430,8 @@ void List::paintEvent(QPaintEvent *e) {
});
p.setBrush(gradient);
p.drawEllipse(outer);
p.setOpacity(1.);
}
p.setOpacity(1.);
}, [&](Single single) {
Expects(single.itemSmall || single.itemFull);
@ -710,19 +711,24 @@ void List::contextMenuEvent(QContextMenuEvent *e) {
const auto id = item.user.id;
const auto hidden = item.user.hidden;
_menu->addAction(u"View Profile"_q, [=] {
_menu->addAction(tr::lng_context_view_profile(tr::now), [=] {
_showProfileRequests.fire_copy(id);
});
_menu->addAction(hidden ? u"Show in Chats"_q : u"Hide"_q, [=] {
_toggleShown.fire({ .id = id, .shown = hidden });
});
QObject::connect(_menu.get(), &QObject::destroyed, [=] {
_menu->addAction(hidden
? tr::lng_stories_show_in_chats(tr::now)
: tr::lng_stories_hide_to_contacts(tr::now),
[=] { _toggleShown.fire({ .id = id, .shown = hidden }); });
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));
if (_menu->empty()) {
_menu = nullptr;
} else {

View File

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "base/qt/qt_compare.h"
#include "base/weak_ptr.h"
#include "ui/rp_widget.h"
class QPainter;
@ -160,6 +161,7 @@ private:
int _pressed = -1;
base::unique_qptr<Ui::PopupMenu> _menu;
base::has_weak_ptr _menuGuard;
};

View File

@ -3061,7 +3061,11 @@ void OverlayWidget::show(OpenRequest request) {
setSession(&photo->session());
if (story) {
setContext(StoriesContext{ story->peer(), story->id() });
setContext(StoriesContext{
story->peer(),
story->id(),
request.storiesList(),
});
} else if (contextPeer) {
setContext(contextPeer);
} else if (contextItem) {