mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-19 07:37:11 +02:00
Track all required sessions notifications.
This commit is contained in:
parent
93c6038992
commit
e6294f48de
9 changed files with 194 additions and 78 deletions
|
@ -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 §ion = 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) {
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Add table
Reference in a new issue