mirror of https://github.com/procxx/kepka.git
Show info media overview using Overview::Layout.
This commit is contained in:
parent
7905694b31
commit
ecbc0ae57e
|
@ -510,9 +510,9 @@ SharedMediaMergedSlice::SharedMediaMergedSlice(
|
|||
Key key,
|
||||
SharedMediaSlice part,
|
||||
base::optional<SharedMediaSlice> migrated)
|
||||
: _key(key)
|
||||
, _part(std::move(part))
|
||||
, _migrated(std::move(migrated)) {
|
||||
: _key(key)
|
||||
, _part(std::move(part))
|
||||
, _migrated(std::move(migrated)) {
|
||||
}
|
||||
|
||||
base::optional<int> SharedMediaMergedSlice::fullCount() const {
|
||||
|
|
|
@ -32,6 +32,8 @@ InfoToggle {
|
|||
rippleAreaPadding: pixels;
|
||||
}
|
||||
|
||||
infoMediaHeaderFg: windowFg;
|
||||
|
||||
infoToggleCheckbox: Checkbox(defaultCheckbox) {
|
||||
margin: margins(0px, 0px, 0px, 0px);
|
||||
rippleBgActive: windowBgOver;
|
||||
|
@ -113,7 +115,7 @@ infoLayerTopBar: InfoTopBar {
|
|||
bg: boxBg;
|
||||
}
|
||||
|
||||
infoMinimalWidth: 320px;
|
||||
infoMinimalWidth: 324px;
|
||||
infoDesiredWidth: 360px;
|
||||
infoMinimalLayerMargin: 48px;
|
||||
|
||||
|
@ -342,3 +344,11 @@ infoMembersCancelSearch: CrossButton {
|
|||
}
|
||||
}
|
||||
infoMembersSearchTop: 15px;
|
||||
|
||||
infoMediaHeaderStyle: TextStyle(semiboldTextStyle) {
|
||||
}
|
||||
infoMediaHeaderHeight: 28px;
|
||||
infoMediaHeaderPosition: point(14px, 6px);
|
||||
infoMediaSkip: 6px;
|
||||
infoMediaMargin: margins(0px, 6px, 0px, 2px);
|
||||
infoMediaMinGridSize: minPhotoSize;
|
||||
|
|
|
@ -79,6 +79,9 @@ void WrapWidget::createTabs() {
|
|||
sections.push_back(lang(lng_profile_info_section).toUpper());
|
||||
sections.push_back(lang(lng_info_tab_media).toUpper());
|
||||
_topTabs->setSections(sections);
|
||||
_topTabs->setActiveSection(static_cast<int>(_tab));
|
||||
_topTabs->finishAnimating();
|
||||
|
||||
_topTabs->sectionActivated()
|
||||
| rpl::map([](int index) { return static_cast<Tab>(index); })
|
||||
| rpl::start_with_next(
|
||||
|
@ -111,6 +114,9 @@ void WrapWidget::forceContentRepaint() {
|
|||
}
|
||||
|
||||
void WrapWidget::showTab(Tab tab) {
|
||||
if (_tab == tab) {
|
||||
return;
|
||||
}
|
||||
Expects(_content != nullptr);
|
||||
auto direction = (tab > _tab)
|
||||
? SlideDirection::FromRight
|
||||
|
@ -132,6 +138,7 @@ void WrapWidget::showTab(Tab tab) {
|
|||
showAnimated(direction, animationParams);
|
||||
|
||||
_anotherTabMemento = std::move(newAnotherMemento);
|
||||
_tab = tab;
|
||||
}
|
||||
|
||||
void WrapWidget::setupTabbedTop(const Section §ion) {
|
||||
|
@ -241,7 +248,6 @@ void WrapWidget::finishShowContent() {
|
|||
_topShadow->finishAnimating();
|
||||
if (_topTabs) {
|
||||
_topTabs->raise();
|
||||
_topTabs->finishAnimating();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
#include "info/profile/info_profile_button.h"
|
||||
#include "info/profile/info_profile_icon.h"
|
||||
#include "ui/widgets/discrete_sliders.h"
|
||||
#include "ui/widgets/shadow.h"
|
||||
#include "ui/wrap/vertical_layout.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "lang/lang_keys.h"
|
||||
|
@ -82,8 +83,12 @@ void InnerWidget::setupOtherTypes(rpl::producer<Wrap> &&wrap) {
|
|||
}
|
||||
|
||||
void InnerWidget::createOtherTypes() {
|
||||
_otherTabsShadow.create(this);
|
||||
_otherTabsShadow->show();
|
||||
|
||||
_otherTabs = nullptr;
|
||||
_otherTypes.create(this);
|
||||
_otherTypes->show();
|
||||
|
||||
createTypeButtons();
|
||||
_otherTypes->add(object_ptr<BoxContentDivider>(_otherTypes));
|
||||
|
@ -157,6 +162,9 @@ void InnerWidget::createTabs() {
|
|||
sections.push_back(lang(lng_media_type_videos).toUpper());
|
||||
sections.push_back(lang(lng_media_type_files).toUpper());
|
||||
_otherTabs->setSections(sections);
|
||||
_otherTabs->setActiveSection(*TypeToTabIndex(type()));
|
||||
_otherTabs->finishAnimating();
|
||||
|
||||
_otherTabs->sectionActivated()
|
||||
| rpl::map([](int index) { return TabIndexToType(index); })
|
||||
| rpl::start_with_next(
|
||||
|
@ -204,7 +212,14 @@ void InnerWidget::switchToTab(Memento &&memento) {
|
|||
auto type = memento.section().mediaType();
|
||||
_list = setupList(controller(), peer(), type);
|
||||
restoreState(&memento);
|
||||
_otherTabs->setActiveSection(*TypeToTabIndex(type));
|
||||
_list->show();
|
||||
_list->resizeToWidth(width());
|
||||
refreshHeight();
|
||||
if (_otherTypes) {
|
||||
_otherTabsShadow->raise();
|
||||
_otherTypes->raise();
|
||||
_otherTabs->setActiveSection(*TypeToTabIndex(type));
|
||||
}
|
||||
}
|
||||
|
||||
not_null<Window::Controller*> InnerWidget::controller() const {
|
||||
|
@ -239,6 +254,7 @@ int InnerWidget::resizeGetHeight(int newWidth) {
|
|||
|
||||
if (_otherTypes) {
|
||||
_otherTypes->resizeToWidth(newWidth);
|
||||
_otherTabsShadow->resizeToWidth(newWidth);
|
||||
}
|
||||
_list->resizeToWidth(newWidth);
|
||||
return recountHeight();
|
||||
|
@ -255,7 +271,8 @@ int InnerWidget::recountHeight() {
|
|||
auto top = 0;
|
||||
if (_otherTypes) {
|
||||
_otherTypes->moveToLeft(0, top);
|
||||
top += _otherTypes->heightNoMargins();
|
||||
top += _otherTypes->heightNoMargins() - st::lineWidth;
|
||||
_otherTabsShadow->moveToLeft(0, top);
|
||||
}
|
||||
if (_list) {
|
||||
_list->moveToLeft(0, top);
|
||||
|
|
|
@ -78,6 +78,7 @@ private:
|
|||
|
||||
Ui::SettingsSlider *_otherTabs = nullptr;
|
||||
object_ptr<Ui::VerticalLayout> _otherTypes = { nullptr };
|
||||
object_ptr<Ui::PlainShadow> _otherTabsShadow = { nullptr };
|
||||
object_ptr<ListWidget> _list = { nullptr };
|
||||
|
||||
int _visibleTop = 0;
|
||||
|
|
|
@ -20,8 +20,271 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
*/
|
||||
#include "info/media/info_media_list_widget.h"
|
||||
|
||||
#include "overview/overview_layout.h"
|
||||
#include "history/history_media_types.h"
|
||||
#include "window/themes/window_theme.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "styles/style_overview.h"
|
||||
#include "styles/style_info.h"
|
||||
|
||||
namespace Layout = Overview::Layout;
|
||||
|
||||
namespace Info {
|
||||
namespace Media {
|
||||
namespace {
|
||||
|
||||
constexpr auto kIdsLimit = 256;
|
||||
|
||||
using ItemBase = Layout::ItemBase;
|
||||
|
||||
} // namespace
|
||||
|
||||
ListWidget::CachedItem::CachedItem(std::unique_ptr<ItemBase> item)
|
||||
: item(std::move(item)) {
|
||||
}
|
||||
|
||||
ListWidget::CachedItem::~CachedItem() = default;
|
||||
|
||||
class ListWidget::Section {
|
||||
public:
|
||||
Section(Type type) : _type(type) {
|
||||
}
|
||||
|
||||
bool addItem(not_null<ItemBase*> item);
|
||||
bool empty() const {
|
||||
return _items.empty();
|
||||
}
|
||||
|
||||
void resizeToWidth(int newWidth);
|
||||
int height() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
void paint(
|
||||
Painter &p,
|
||||
QRect clip,
|
||||
int outerWidth,
|
||||
TimeMs ms) const;
|
||||
|
||||
private:
|
||||
int headerHeight() const;
|
||||
void appendItem(not_null<ItemBase*> item);
|
||||
void setHeader(not_null<ItemBase*> item);
|
||||
bool belongsHere(not_null<ItemBase*> item) const;
|
||||
int countRowHeight(not_null<ItemBase*> item) const;
|
||||
|
||||
Type _type = Type::Photo;
|
||||
Text _header;
|
||||
std::vector<not_null<ItemBase*>> _items;
|
||||
int _itemsLeft = 0;
|
||||
int _itemsTop = 0;
|
||||
int _itemWidth = 0;
|
||||
int _itemsInRow = 1;
|
||||
int _rowsCount = 0;
|
||||
int _height = 0;
|
||||
|
||||
};
|
||||
|
||||
bool ListWidget::Section::addItem(not_null<ItemBase*> item) {
|
||||
if (_items.empty() || belongsHere(item)) {
|
||||
if (_items.empty()) setHeader(item);
|
||||
appendItem(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ListWidget::Section::setHeader(not_null<ItemBase*> item) {
|
||||
auto text = [&] {
|
||||
auto date = item->getItem()->date.date();
|
||||
switch (_type) {
|
||||
case Type::Photo:
|
||||
case Type::Video:
|
||||
case Type::RoundFile:
|
||||
case Type::VoiceFile:
|
||||
case Type::File:
|
||||
return langMonthFull(date);
|
||||
|
||||
case Type::Link:
|
||||
return langDayOfMonthFull(date);
|
||||
|
||||
case Type::MusicFile:
|
||||
return QString();
|
||||
}
|
||||
Unexpected("Type in ListWidget::Section::setHeader()");
|
||||
}();
|
||||
_header.setText(st::infoMediaHeaderStyle, text);
|
||||
}
|
||||
|
||||
bool ListWidget::Section::belongsHere(
|
||||
not_null<ItemBase*> item) const {
|
||||
Expects(!_items.empty());
|
||||
auto date = item->getItem()->date.date();
|
||||
auto myDate = _items.back()->getItem()->date.date();
|
||||
|
||||
switch (_type) {
|
||||
case Type::Photo:
|
||||
case Type::Video:
|
||||
case Type::RoundFile:
|
||||
case Type::VoiceFile:
|
||||
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 ListWidget::Section::belongsHere()");
|
||||
}
|
||||
|
||||
int ListWidget::Section::countRowHeight(
|
||||
not_null<ItemBase*> item) const {
|
||||
switch (_type) {
|
||||
case Type::Photo:
|
||||
case Type::Video:
|
||||
case Type::RoundFile:
|
||||
return _itemWidth + st::infoMediaSkip;
|
||||
|
||||
case Type::VoiceFile:
|
||||
case Type::File:
|
||||
case Type::Link:
|
||||
case Type::MusicFile:
|
||||
return item->height();
|
||||
}
|
||||
Unexpected("Type in ListWidget::Section::countRowHeight()");
|
||||
}
|
||||
|
||||
void ListWidget::Section::appendItem(not_null<ItemBase*> item) {
|
||||
_items.push_back(item);
|
||||
}
|
||||
|
||||
void ListWidget::Section::paint(
|
||||
Painter &p,
|
||||
QRect clip,
|
||||
int outerWidth,
|
||||
TimeMs ms) const {
|
||||
auto baseIndex = 0;
|
||||
auto top = _itemsTop;
|
||||
auto header = headerHeight();
|
||||
if (header) {
|
||||
p.setPen(st::infoMediaHeaderFg);
|
||||
_header.drawLeftElided(
|
||||
p,
|
||||
st::infoMediaHeaderPosition.x(),
|
||||
st::infoMediaHeaderPosition.y(),
|
||||
outerWidth - 2 * st::infoMediaHeaderPosition.x(),
|
||||
outerWidth);
|
||||
top += header;
|
||||
}
|
||||
auto fromitem = floorclamp(
|
||||
clip.x() - _itemsLeft,
|
||||
_itemWidth,
|
||||
0,
|
||||
_itemsInRow);
|
||||
auto tillitem = ceilclamp(
|
||||
clip.x() + clip.width() - _itemsLeft,
|
||||
_itemWidth,
|
||||
0,
|
||||
_itemsInRow);
|
||||
Layout::PaintContext context(ms, false);
|
||||
context.isAfterDate = (header > 0);
|
||||
|
||||
// #TODO ranges, binary search for visible slice.
|
||||
for (auto row = 0; row != _rowsCount; ++row) {
|
||||
auto rowHeight = countRowHeight(_items[baseIndex]);
|
||||
auto increment = gsl::finally([&] {
|
||||
top += rowHeight;
|
||||
baseIndex += _itemsInRow;
|
||||
context.isAfterDate = false;
|
||||
});
|
||||
|
||||
if (top >= clip.y() + clip.height()) {
|
||||
break;
|
||||
} else if (top + rowHeight <= clip.y()) {
|
||||
continue;
|
||||
}
|
||||
for (auto col = fromitem; col != tillitem; ++col) {
|
||||
auto index = baseIndex + col;
|
||||
if (index >= int(_items.size())) {
|
||||
break;
|
||||
}
|
||||
auto item = _items[index];
|
||||
auto left = _itemsLeft
|
||||
+ col * (_itemWidth + st::infoMediaSkip);
|
||||
p.translate(left, top);
|
||||
item->paint(
|
||||
p,
|
||||
clip.translated(-left, -top),
|
||||
TextSelection(),
|
||||
&context);
|
||||
p.translate(-left, -top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ListWidget::Section::headerHeight() const {
|
||||
return _header.isEmpty() ? 0 : st::infoMediaHeaderHeight;
|
||||
}
|
||||
|
||||
void ListWidget::Section::resizeToWidth(int newWidth) {
|
||||
auto minWidth = st::infoMediaMinGridSize + st::infoMediaSkip * 2;
|
||||
if (newWidth < minWidth) {
|
||||
return;
|
||||
}
|
||||
|
||||
_height = headerHeight();
|
||||
switch (_type) {
|
||||
case Type::Photo:
|
||||
case Type::Video:
|
||||
case Type::RoundFile: {
|
||||
_itemsLeft = st::infoMediaSkip;
|
||||
_itemsTop = st::infoMediaSkip;
|
||||
_itemsInRow = (newWidth - _itemsLeft)
|
||||
/ (st::infoMediaMinGridSize + st::infoMediaSkip);
|
||||
_itemWidth = ((newWidth - _itemsLeft) / _itemsInRow)
|
||||
- st::infoMediaSkip;
|
||||
auto itemHeight = _itemWidth + st::infoMediaSkip;
|
||||
_rowsCount = (int(_items.size()) + _itemsInRow - 1)
|
||||
/ _itemsInRow;
|
||||
_height += _itemsTop + _rowsCount * itemHeight;
|
||||
} break;
|
||||
|
||||
case Type::VoiceFile:
|
||||
case Type::File:
|
||||
case Type::MusicFile: {
|
||||
_itemsLeft = 0;
|
||||
_itemsTop = 0;
|
||||
_itemsInRow = 1;
|
||||
_itemWidth = newWidth;
|
||||
auto itemHeight = _items.empty() ? 0 : _items.front()->height();
|
||||
_rowsCount = _items.size();
|
||||
_height += _rowsCount * itemHeight;
|
||||
} break;
|
||||
|
||||
case Type::Link:
|
||||
_itemsLeft = 0;
|
||||
_itemsTop = 0;
|
||||
_itemsInRow = 1;
|
||||
_itemWidth = newWidth;
|
||||
auto top = 0;
|
||||
for (auto item : _items) {
|
||||
top += item->resizeGetHeight(_itemWidth);
|
||||
}
|
||||
_height += top;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_type != Type::Link) {
|
||||
for (auto item : _items) {
|
||||
item->resizeGetHeight(_itemWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListWidget::ListWidget(
|
||||
QWidget *parent,
|
||||
|
@ -31,8 +294,194 @@ ListWidget::ListWidget(
|
|||
: RpWidget(parent)
|
||||
, _controller(controller)
|
||||
, _peer(peer)
|
||||
, _type(type) {
|
||||
, _type(type)
|
||||
, _slice(sliceKey()) {
|
||||
refreshViewer();
|
||||
ObservableViewer(*Window::Theme::Background())
|
||||
| rpl::start_with_next([this](const auto &update) {
|
||||
if (update.paletteChanged()) {
|
||||
invalidatePaletteCache();
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void ListWidget::invalidatePaletteCache() {
|
||||
for (auto &layout : _layouts) {
|
||||
layout.second.item->invalidateCache();
|
||||
}
|
||||
}
|
||||
|
||||
SharedMediaMergedSlice::Key ListWidget::sliceKey() const {
|
||||
auto universalId = _universalAroundId;
|
||||
using Key = SharedMediaMergedSlice::Key;
|
||||
if (auto migrateTo = _peer->migrateTo()) {
|
||||
return Key(migrateTo->id, _peer->id, _type, universalId);
|
||||
} else if (auto migrateFrom = _peer->migrateFrom()) {
|
||||
return Key(_peer->id, migrateFrom->id, _type, universalId);
|
||||
}
|
||||
return Key(_peer->id, 0, _type, universalId);
|
||||
}
|
||||
|
||||
void ListWidget::refreshViewer() {
|
||||
SharedMediaMergedViewer(
|
||||
sliceKey(),
|
||||
countIdsLimit(),
|
||||
countIdsLimit())
|
||||
| rpl::start_with_next([this](SharedMediaMergedSlice &&slice) {
|
||||
_slice = std::move(slice);
|
||||
refreshRows();
|
||||
}, _viewerLifetime);
|
||||
}
|
||||
|
||||
int ListWidget::countIdsLimit() const {
|
||||
return kIdsLimit;
|
||||
}
|
||||
|
||||
ItemBase *ListWidget::getLayout(const FullMsgId &itemId) {
|
||||
auto it = _layouts.find(itemId);
|
||||
if (it == _layouts.end()) {
|
||||
if (auto layout = createLayout(itemId, _type)) {
|
||||
layout->initDimensions();
|
||||
it = _layouts.emplace(itemId, std::move(layout)).first;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
it->second.stale = false;
|
||||
return it->second.item.get();
|
||||
}
|
||||
|
||||
std::unique_ptr<ItemBase> ListWidget::createLayout(
|
||||
const FullMsgId &itemId,
|
||||
Type type) {
|
||||
auto item = App::histItemById(itemId);
|
||||
if (!item) {
|
||||
return nullptr;
|
||||
}
|
||||
auto getPhoto = [&]() -> PhotoData* {
|
||||
if (auto media = item->getMedia()) {
|
||||
if (media->type() == MediaTypePhoto) {
|
||||
return static_cast<HistoryPhoto*>(media)->photo();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
auto getFile = [&]() -> DocumentData* {
|
||||
if (auto media = item->getMedia()) {
|
||||
return media->getDocument();
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
switch (type) {
|
||||
case Type::Photo:
|
||||
if (auto photo = getPhoto()) {
|
||||
return std::make_unique<Layout::Photo>(photo, item);
|
||||
}
|
||||
return nullptr;
|
||||
case Type::Video:
|
||||
if (auto file = getFile()) {
|
||||
return std::make_unique<Layout::Video>(file, item);
|
||||
}
|
||||
return nullptr;
|
||||
case Type::File:
|
||||
if (auto file = getFile()) {
|
||||
return std::make_unique<Layout::Document>(file, item, st::overviewFileLayout);
|
||||
}
|
||||
return nullptr;
|
||||
case Type::MusicFile:
|
||||
if (auto file = getFile()) {
|
||||
return std::make_unique<Layout::Document>(file, item, st::overviewFileLayout);
|
||||
}
|
||||
return nullptr;
|
||||
case Type::VoiceFile:
|
||||
if (auto file = getFile()) {
|
||||
return std::make_unique<Layout::Voice>(file, item, st::overviewFileLayout);
|
||||
}
|
||||
return nullptr;
|
||||
case Type::Link:
|
||||
return std::make_unique<Layout::Link>(item->getMedia(), item);
|
||||
case Type::RoundFile:
|
||||
return nullptr;
|
||||
}
|
||||
Unexpected("Type in ListWidget::createLayout()");
|
||||
}
|
||||
|
||||
void ListWidget::refreshRows() {
|
||||
markLayoutsStale();
|
||||
|
||||
_sections.clear();
|
||||
auto section = Section(_type);
|
||||
auto count = _slice.size();
|
||||
for (auto i = count; i != 0;) {
|
||||
auto itemId = _slice[--i];
|
||||
if (auto layout = getLayout(itemId)) {
|
||||
if (!section.addItem(layout)) {
|
||||
_sections.push_back(std::move(section));
|
||||
section = Section(_type);
|
||||
section.addItem(layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!section.empty()) {
|
||||
_sections.push_back(std::move(section));
|
||||
}
|
||||
|
||||
clearStaleLayouts();
|
||||
|
||||
resizeToWidth(width());
|
||||
}
|
||||
|
||||
void ListWidget::markLayoutsStale() {
|
||||
for (auto &layout : _layouts) {
|
||||
layout.second.stale = true;
|
||||
}
|
||||
}
|
||||
|
||||
int ListWidget::resizeGetHeight(int newWidth) {
|
||||
for (auto §ion : _sections) {
|
||||
section.resizeToWidth(newWidth);
|
||||
}
|
||||
return recountHeight();
|
||||
}
|
||||
|
||||
void ListWidget::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
|
||||
auto outerWidth = width();
|
||||
auto clip = e->rect();
|
||||
auto ms = getms();
|
||||
auto top = st::infoMediaMargin.top();
|
||||
p.translate(0, top);
|
||||
clip = clip.translated(0, -top);
|
||||
for (auto §ion : _sections) {
|
||||
section.paint(p, clip, outerWidth, ms);
|
||||
auto height = section.height();
|
||||
p.translate(0, height);
|
||||
clip = clip.translated(0, -height);
|
||||
}
|
||||
}
|
||||
|
||||
int ListWidget::recountHeight() {
|
||||
auto result = 0;
|
||||
for (auto §ion : _sections) {
|
||||
result += section.height();
|
||||
}
|
||||
return st::infoMediaMargin.top()
|
||||
+ result
|
||||
+ st::infoMediaMargin.bottom();
|
||||
}
|
||||
|
||||
void ListWidget::clearStaleLayouts() {
|
||||
for (auto i = _layouts.begin(); i != _layouts.end();) {
|
||||
if (i->second.stale) {
|
||||
i = _layouts.erase(i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ListWidget::~ListWidget() = default;
|
||||
|
||||
} // namespace Media
|
||||
} // namespace Info
|
||||
|
|
|
@ -22,6 +22,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
|||
|
||||
#include "ui/rp_widget.h"
|
||||
#include "info/media/info_media_widget.h"
|
||||
#include "history/history_shared_media.h"
|
||||
|
||||
namespace Overview {
|
||||
namespace Layout {
|
||||
class ItemBase;
|
||||
} // namespace Layout
|
||||
} // namespace Overview
|
||||
|
||||
namespace Window {
|
||||
class Controller;
|
||||
|
@ -49,11 +56,51 @@ public:
|
|||
return _type;
|
||||
}
|
||||
|
||||
~ListWidget();
|
||||
|
||||
protected:
|
||||
int resizeGetHeight(int newWidth) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
|
||||
private:
|
||||
using ItemBase = Overview::Layout::ItemBase;
|
||||
|
||||
int recountHeight();
|
||||
|
||||
void refreshViewer();
|
||||
void invalidatePaletteCache();
|
||||
void refreshRows();
|
||||
int countIdsLimit() const;
|
||||
SharedMediaMergedSlice::Key sliceKey() const;
|
||||
ItemBase *getLayout(const FullMsgId &itemId);
|
||||
std::unique_ptr<ItemBase> createLayout(
|
||||
const FullMsgId &itemId,
|
||||
Type type);
|
||||
|
||||
void markLayoutsStale();
|
||||
void clearStaleLayouts();
|
||||
|
||||
not_null<Window::Controller*> _controller;
|
||||
not_null<PeerData*> _peer;
|
||||
Type _type = Type::Photo;
|
||||
|
||||
MsgId _universalAroundId = ServerMaxMsgId - 1;
|
||||
SharedMediaMergedSlice _slice;
|
||||
|
||||
struct CachedItem {
|
||||
CachedItem(std::unique_ptr<ItemBase> item);
|
||||
~CachedItem();
|
||||
|
||||
std::unique_ptr<ItemBase> item;
|
||||
bool stale = false;
|
||||
};
|
||||
std::map<FullMsgId, CachedItem> _layouts;
|
||||
|
||||
class Section;
|
||||
std::vector<Section> _sections;
|
||||
|
||||
rpl::lifetime _viewerLifetime;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Media
|
||||
|
|
|
@ -191,13 +191,15 @@ rpl::producer<int> MembersCountValue(
|
|||
rpl::producer<int> SharedMediaCountValue(
|
||||
not_null<PeerData*> peer,
|
||||
Storage::SharedMediaType type) {
|
||||
auto initial = peer->migrateFrom() ? peer->migrateFrom() : peer;
|
||||
auto migrated = initial->migrateTo();
|
||||
auto real = peer->migrateTo() ? peer->migrateTo() : peer;
|
||||
auto migrated = real->migrateFrom()
|
||||
? real->migrateFrom()
|
||||
: nullptr;
|
||||
auto aroundId = 0;
|
||||
auto limit = 0;
|
||||
auto updated = SharedMediaMergedViewer(
|
||||
SharedMediaMergedSlice::Key(
|
||||
peer->id,
|
||||
real->id,
|
||||
migrated ? migrated->id : 0,
|
||||
type,
|
||||
aroundId),
|
||||
|
|
|
@ -69,13 +69,13 @@ public:
|
|||
ItemBase(HistoryItem *parent) : _parent(parent) {
|
||||
}
|
||||
|
||||
ItemBase *toMediaItem() override {
|
||||
ItemBase *toMediaItem() final override {
|
||||
return this;
|
||||
}
|
||||
const ItemBase *toMediaItem() const override {
|
||||
const ItemBase *toMediaItem() const final override {
|
||||
return this;
|
||||
}
|
||||
HistoryItem *getItem() const override {
|
||||
HistoryItem *getItem() const final override {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue