Track all required sessions notifications.

This commit is contained in:
John Preston 2022-02-24 21:19:27 +03:00
parent 93c6038992
commit e6294f48de
9 changed files with 194 additions and 78 deletions

View file

@ -13,7 +13,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_download_manager.h"
#include "data/data_document.h"
#include "data/data_media_types.h"
#include "data/data_session.h"
#include "main/main_session.h"
#include "main/main_account.h"
#include "history/history_item.h"
#include "history/history.h"
#include "core/application.h"
#include "storage/storage_shared_media.h"
#include "layout/layout_selection.h"
@ -47,6 +51,20 @@ rpl::producer<bool> Provider::hasSelectRestrictionChanges() {
return rpl::never<bool>();
}
bool Provider::sectionHasFloatingHeader() {
return false;
}
QString Provider::sectionTitle(not_null<const BaseLayout*> item) {
return QString();
}
bool Provider::sectionItemBelongsHere(
not_null<const BaseLayout*> item,
not_null<const BaseLayout*> previous) {
return true;
}
bool Provider::isPossiblyMyItem(not_null<const HistoryItem*> item) {
return true;
}
@ -85,6 +103,7 @@ void Provider::refreshViewer() {
added = true;
_downloading.emplace(item);
_elements.push_back(Element{ item, id.started });
trackItemSession(item);
}
}
}
@ -104,6 +123,24 @@ void Provider::refreshViewer() {
}, _lifetime);
}
void Provider::trackItemSession(not_null<const HistoryItem*> item) {
const auto session = &item->history()->session();
if (_trackedSessions.contains(session)) {
return;
}
auto &lifetime = _trackedSessions.emplace(session).first->second;
session->data().itemRemoved(
) | rpl::start_with_next([this](auto item) {
itemRemoved(item);
}, lifetime);
session->account().sessionChanges(
) | rpl::take(1) | rpl::start_with_next([=] {
_trackedSessions.remove(session);
}, lifetime);
}
rpl::producer<> Provider::refreshed() {
return _refreshed.events();
}
@ -117,7 +154,9 @@ std::vector<ListSection> Provider::fillSections(
return {};
}
auto result = std::vector<ListSection>(1, ListSection(Type::File));
auto result = std::vector<ListSection>(
1,
ListSection(Type::File, sectionDelegate()));
auto &section = result.back();
for (const auto &element : _elements) {
if (auto layout = getLayout(element, delegate)) {
@ -172,6 +211,13 @@ bool Provider::isAfter(
return false;
}
void Provider::itemRemoved(not_null<const HistoryItem*> item) {
if (const auto i = _layouts.find(item); i != end(_layouts)) {
_layoutRemoved.fire(i->second.item.get());
_layouts.erase(i);
}
}
BaseLayout *Provider::getLayout(
Element element,
not_null<Overview::Layout::Delegate*> delegate) {

View file

@ -15,7 +15,9 @@ class AbstractController;
namespace Info::Downloads {
class Provider final : public Media::ListProvider {
class Provider final
: public Media::ListProvider
, private Media::ListSectionDelegate {
public:
explicit Provider(not_null<AbstractController*> controller);
@ -65,10 +67,18 @@ private:
int64 started = 0; // unixtime * 1000
};
bool sectionHasFloatingHeader() override;
QString sectionTitle(not_null<const Media::BaseLayout*> item) override;
bool sectionItemBelongsHere(
not_null<const Media::BaseLayout*> item,
not_null<const Media::BaseLayout*> previous) override;
void itemRemoved(not_null<const HistoryItem*> item);
void markLayoutsStale();
void clearStaleLayouts();
void trackItemSession(not_null<const HistoryItem*> item);
[[nodiscard]] Media::BaseLayout *getLayout(
Element element,
not_null<Overview::Layout::Delegate*> delegate);
@ -83,10 +93,14 @@ private:
base::flat_set<not_null<const HistoryItem*>> _downloading;
base::flat_set<not_null<const HistoryItem*>> _downloaded;
std::unordered_map<not_null<HistoryItem*>, Media::CachedItem> _layouts;
std::unordered_map<
not_null<const HistoryItem*>,
Media::CachedItem> _layouts;
rpl::event_stream<not_null<Media::BaseLayout*>> _layoutRemoved;
rpl::event_stream<> _refreshed;
base::flat_map<not_null<Main::Session*>, rpl::lifetime> _trackedSessions;
rpl::lifetime _lifetime;
};

View file

@ -85,6 +85,20 @@ bool ChangeItemSelection(
not_null<const HistoryItem*> item,
TextSelection selection);
class ListSectionDelegate {
public:
[[nodiscard]] virtual bool sectionHasFloatingHeader() = 0;
[[nodiscard]] virtual QString sectionTitle(
not_null<const BaseLayout*> item) = 0;
[[nodiscard]] virtual bool sectionItemBelongsHere(
not_null<const BaseLayout*> item,
not_null<const BaseLayout*> previous) = 0;
[[nodiscard]] not_null<ListSectionDelegate*> sectionDelegate() {
return this;
}
};
class ListProvider {
public:
[[nodiscard]] virtual Type type() = 0;
@ -133,7 +147,6 @@ public:
Fn<void(ListScrollTopState)> restoreScrollState) = 0;
virtual ~ListProvider() = default;
};
} // namespace Info::Media

View file

@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/media/info_media_list_section.h"
#include "storage/storage_shared_media.h"
#include "lang/lang_keys.h"
#include "layout/layout_selection.h"
#include "styles/style_info.h"
@ -17,27 +16,12 @@ namespace {
constexpr auto kFloatingHeaderAlpha = 0.9;
[[nodiscard]] bool HasFloatingHeader(Type type) {
switch (type) {
case Type::Photo:
case Type::GIF:
case Type::Video:
case Type::RoundFile:
case Type::RoundVoiceFile:
case Type::MusicFile:
return false;
case Type::File:
case Type::Link:
return true;
}
Unexpected("Type in HasFloatingHeader()");
}
} // namespace
ListSection::ListSection(Type type)
ListSection::ListSection(Type type, not_null<ListSectionDelegate*> delegate)
: _type(type)
, _hasFloatingHeader(HasFloatingHeader(type))
, _delegate(delegate)
, _hasFloatingHeader(delegate->sectionHasFloatingHeader())
, _mosaic(st::emojiPanWidth - st::inlineResultsLeft) {
}
@ -87,54 +71,14 @@ void ListSection::finishSection() {
}
void ListSection::setHeader(not_null<BaseLayout*> item) {
auto text = [&] {
auto date = item->dateTime().date();
switch (_type) {
case Type::Photo:
case Type::GIF:
case Type::Video:
case Type::RoundFile:
case Type::RoundVoiceFile:
case Type::File:
return langMonthFull(date);
case Type::Link:
return langDayOfMonthFull(date);
case Type::MusicFile:
return QString();
}
Unexpected("Type in ListSection::setHeader()");
}();
_header.setText(st::infoMediaHeaderStyle, text);
_header.setText(st::infoMediaHeaderStyle, _delegate->sectionTitle(item));
}
bool ListSection::belongsHere(
not_null<BaseLayout*> item) const {
Expects(!_items.empty());
auto date = item->dateTime().date();
auto myDate = _items.back()->dateTime().date();
switch (_type) {
case Type::Photo:
case Type::GIF:
case Type::Video:
case Type::RoundFile:
case Type::RoundVoiceFile:
case Type::File:
return date.year() == myDate.year()
&& date.month() == myDate.month();
case Type::Link:
return date.year() == myDate.year()
&& date.month() == myDate.month()
&& date.day() == myDate.day();
case Type::MusicFile:
return true;
}
Unexpected("Type in ListSection::belongsHere()");
return _delegate->sectionItemBelongsHere(item, _items.back());
}
void ListSection::appendItem(not_null<BaseLayout*> item) {
@ -279,6 +223,10 @@ auto ListSection::findItemAfterBottom(
});
}
const ListSection::Items &ListSection::items() const {
return _items;
}
void ListSection::paint(
Painter &p,
const ListContext &context,

View file

@ -15,7 +15,7 @@ namespace Info::Media {
class ListSection {
public:
ListSection(Type type);
ListSection(Type type, not_null<ListSectionDelegate*> delegate);
bool addItem(not_null<BaseLayout*> item);
void finishSection();
@ -40,6 +40,9 @@ public:
not_null<BaseLayout*> item) const;
[[nodiscard]] ListFoundItem findItemByPoint(QPoint point) const;
using Items = std::vector<not_null<BaseLayout*>>;
const Items &items() const;
void paint(
Painter &p,
const ListContext &context,
@ -49,8 +52,6 @@ public:
void paintFloatingHeader(Painter &p, int visibleTop, int outerWidth);
private:
using Items = std::vector<not_null<BaseLayout*>>;
[[nodiscard]] int headerHeight() const;
void appendItem(not_null<BaseLayout*> item);
void setHeader(not_null<BaseLayout*> item);
@ -72,6 +73,8 @@ private:
void refreshHeight();
Type _type = Type{};
not_null<ListSectionDelegate*> _delegate;
bool _hasFloatingHeader = false;
Ui::Text::String _header;
Items _items;

View file

@ -37,6 +37,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/inactive_press.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "main/main_account.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "base/platform/base_platform_info.h"
@ -158,7 +159,7 @@ void ListWidget::start() {
if (_controller->isDownloads()) {
_provider->refreshViewer();
} else {
subscribeToSession(&session());
subscribeToSession(&session(), lifetime());
_controller->mediaSourceQueryValue(
) | rpl::start_with_next([this] {
@ -169,26 +170,28 @@ void ListWidget::start() {
setupSelectRestriction();
}
void ListWidget::subscribeToSession(not_null<Main::Session*> session) {
void ListWidget::subscribeToSession(
not_null<Main::Session*> session,
rpl::lifetime &lifetime) {
session->downloaderTaskFinished(
) | rpl::start_with_next([=] {
update();
}, lifetime());
}, lifetime);
session->data().itemLayoutChanged(
) | rpl::start_with_next([this](auto item) {
itemLayoutChanged(item);
}, lifetime());
}, lifetime);
session->data().itemRemoved(
) | rpl::start_with_next([this](auto item) {
itemRemoved(item);
}, lifetime());
}, lifetime);
session->data().itemRepaintRequest(
) | rpl::start_with_next([this](auto item) {
repaintItem(item);
}, lifetime());
}, lifetime);
}
void ListWidget::setupSelectRestriction() {
@ -416,12 +419,30 @@ void ListWidget::openDocument(
showInMediaView);
}
void ListWidget::trackSession(not_null<Main::Session*> session) {
if (_trackedSessions.contains(session)) {
return;
}
auto &lifetime = _trackedSessions.emplace(session).first->second;
subscribeToSession(session, lifetime);
session->account().sessionChanges(
) | rpl::take(1) | rpl::start_with_next([=] {
_trackedSessions.remove(session);
}, lifetime);
}
void ListWidget::refreshRows() {
saveScrollState();
_sections.clear();
_sections = _provider->fillSections(this);
if (_controller->isDownloads() && !_sections.empty()) {
for (const auto &item : _sections.back().items()) {
trackSession(&item->getItem()->history()->session());
}
}
if (const auto count = _provider->fullCount()) {
if (*count > kMediaCountForSearch) {
_controller->setSearchEnabledByContent(true);

View file

@ -145,7 +145,9 @@ private:
void start();
int recountHeight();
void refreshHeight();
void subscribeToSession(not_null<Main::Session*> session);
void subscribeToSession(
not_null<Main::Session*> session,
rpl::lifetime &lifetime);
void setupSelectRestriction();
@ -162,6 +164,7 @@ private:
void refreshViewer();
void refreshRows();
void trackSession(not_null<Main::Session*> session);
[[nodiscard]] SelectedItems collectSelectedItems() const;
[[nodiscard]] MessageIdsList collectSelectedIds() const;
@ -283,6 +286,7 @@ private:
bool _wasSelectedText = false; // was some text selected in current drag action
const std::unique_ptr<DateBadge> _dateBadge;
base::flat_map<not_null<Main::Session*>, rpl::lifetime> _trackedSessions;
base::unique_qptr<Ui::PopupMenu> _contextMenu;
rpl::event_stream<> _checkForHide;

View file

@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "info/info_controller.h"
#include "layout/layout_selection.h"
#include "main/main_session.h"
#include "lang/lang_keys.h"
#include "history/history.h"
#include "history/history_item.h"
#include "data/data_session.h"
@ -121,6 +122,66 @@ rpl::producer<bool> Provider::hasSelectRestrictionChanges() {
}) | rpl::distinct_until_changed() | rpl::skip(1);
}
bool Provider::sectionHasFloatingHeader() {
switch (_type) {
case Type::Photo:
case Type::GIF:
case Type::Video:
case Type::RoundFile:
case Type::RoundVoiceFile:
case Type::MusicFile:
return false;
case Type::File:
case Type::Link:
return true;
}
Unexpected("Type in HasFloatingHeader()");
}
QString Provider::sectionTitle(not_null<const BaseLayout*> item) {
switch (_type) {
case Type::Photo:
case Type::GIF:
case Type::Video:
case Type::RoundFile:
case Type::RoundVoiceFile:
case Type::File:
return langMonthFull(item->dateTime().date());
case Type::Link:
return langDayOfMonthFull(item->dateTime().date());
case Type::MusicFile:
return QString();
}
Unexpected("Type in ListSection::setHeader()");
}
bool Provider::sectionItemBelongsHere(
not_null<const BaseLayout*> item,
not_null<const BaseLayout*> previous) {
const auto date = item->dateTime().date();
const auto sectionDate = previous->dateTime().date();
switch (_type) {
case Type::Photo:
case Type::GIF:
case Type::Video:
case Type::RoundFile:
case Type::RoundVoiceFile:
case Type::File:
return date.year() == sectionDate.year()
&& date.month() == sectionDate.month();
case Type::Link:
return date == sectionDate;
case Type::MusicFile:
return true;
}
Unexpected("Type in ListSection::belongsHere()");
}
bool Provider::isPossiblyMyItem(not_null<const HistoryItem*> item) {
return isPossiblyMyPeerId(item->history()->peer->id);
}
@ -221,7 +282,7 @@ std::vector<ListSection> Provider::fillSections(
const auto guard = gsl::finally([&] { clearStaleLayouts(); });
auto result = std::vector<ListSection>();
auto section = ListSection(_type);
auto section = ListSection(_type, sectionDelegate());
auto count = _slice.size();
for (auto i = count; i != 0;) {
auto universalId = GetUniversalId(_slice[--i]);
@ -229,7 +290,7 @@ std::vector<ListSection> Provider::fillSections(
if (!section.addItem(layout)) {
section.finishSection();
result.push_back(std::move(section));
section = ListSection(_type);
section = ListSection(_type, sectionDelegate());
section.addItem(layout);
}
}

View file

@ -16,7 +16,7 @@ class AbstractController;
namespace Info::Media {
class Provider final : public ListProvider {
class Provider final : public ListProvider, private ListSectionDelegate {
public:
explicit Provider(not_null<AbstractController*> controller);
@ -64,6 +64,12 @@ private:
static constexpr auto kMinimalIdsLimit = 16;
static constexpr auto kDefaultAroundId = (ServerMaxMsgId - 1);
bool sectionHasFloatingHeader() override;
QString sectionTitle(not_null<const BaseLayout*> item) override;
bool sectionItemBelongsHere(
not_null<const BaseLayout*> item,
not_null<const BaseLayout*> previous) override;
[[nodiscard]] bool isPossiblyMyPeerId(PeerId peerId) const;
[[nodiscard]] FullMsgId computeFullId(UniversalMsgId universalId) const;
[[nodiscard]] BaseLayout *getLayout(