Save scroll top state to media memento.

This commit is contained in:
John Preston 2017-10-27 20:41:38 +03:00
parent f6ed3dff7f
commit 15cc4502b4
8 changed files with 104 additions and 22 deletions

View File

@ -150,7 +150,7 @@ infoLayerTopBar: InfoTopBar {
} }
infoMinimalWidth: 324px; infoMinimalWidth: 324px;
infoDesiredWidth: 360px; infoDesiredWidth: 430px;
infoMinimalLayerMargin: 48px; infoMinimalLayerMargin: 48px;
infoTabs: SettingsSlider(defaultTabsSlider) { infoTabs: SettingsSlider(defaultTabsSlider) {

View File

@ -57,6 +57,10 @@ ContentWidget::ContentWidget(
} }
void ContentWidget::resizeEvent(QResizeEvent *e) { void ContentWidget::resizeEvent(QResizeEvent *e) {
updateControlsGeometry();
}
void ContentWidget::updateControlsGeometry() {
auto newScrollTop = _scroll->scrollTop() + _topDelta; auto newScrollTop = _scroll->scrollTop() + _topDelta;
auto scrollGeometry = rect().marginsRemoved( auto scrollGeometry = rect().marginsRemoved(
QMargins(0, _scrollTopSkip, 0, 0)); QMargins(0, _scrollTopSkip, 0, 0));
@ -113,6 +117,10 @@ Ui::RpWidget *ContentWidget::doSetInnerWidget(
int desired) { int desired) {
inner->setVisibleTopBottom(top, bottom); inner->setVisibleTopBottom(top, bottom);
}, _inner->lifetime()); }, _inner->lifetime());
_scrollTopSkip = scrollTopSkip;
updateControlsGeometry();
return _inner; return _inner;
} }

View File

@ -110,6 +110,7 @@ private:
RpWidget *doSetInnerWidget( RpWidget *doSetInnerWidget(
object_ptr<RpWidget> inner, object_ptr<RpWidget> inner,
int scrollTopSkip); int scrollTopSkip);
void updateControlsGeometry();
const not_null<Window::Controller*> _controller; const not_null<Window::Controller*> _controller;
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;

View File

@ -252,9 +252,11 @@ object_ptr<ListWidget> InnerWidget::setupList(
} }
void InnerWidget::saveState(not_null<Memento*> memento) { void InnerWidget::saveState(not_null<Memento*> memento) {
_list->saveState(memento);
} }
void InnerWidget::restoreState(not_null<Memento*> memento) { void InnerWidget::restoreState(not_null<Memento*> memento) {
_list->restoreState(memento);
} }
rpl::producer<SelectedItems> InnerWidget::selectedListValue() const { rpl::producer<SelectedItems> InnerWidget::selectedListValue() const {

View File

@ -720,6 +720,12 @@ bool ListWidget::isMyItem(not_null<const HistoryItem*> item) const {
return (_peer == peer || _peer == peer->migrateTo()); return (_peer == peer || _peer == peer->migrateTo());
} }
bool ListWidget::isPossiblyMyId(FullMsgId fullId) const {
return (fullId.channel != 0)
? (_peer->isChannel() && _peer->bareId() == fullId.channel)
: (!_peer->isChannel() || _peer->migrateFrom());
}
bool ListWidget::isItemLayout( bool ListWidget::isItemLayout(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
BaseLayout *layout) const { BaseLayout *layout) const {
@ -878,6 +884,29 @@ void ListWidget::markLayoutsStale() {
} }
} }
void ListWidget::saveState(not_null<Memento*> memento) {
if (_universalAroundId != kDefaultAroundId) {
memento->setAroundId(computeFullId(_universalAroundId));
memento->setIdsLimit(_idsLimit);
auto state = countScrollState();
memento->setScrollTopItem(computeFullId(state.item));
memento->setScrollTopShift(state.shift);
}
}
void ListWidget::restoreState(not_null<Memento*> memento) {
if (auto limit = memento->idsLimit()) {
auto wasAroundId = memento->aroundId();
if (isPossiblyMyId(wasAroundId)) {
_idsLimit = limit;
_universalAroundId = GetUniversalId(wasAroundId);
_scrollTopState.item = GetUniversalId(memento->scrollTopItem());
_scrollTopState.shift = memento->scrollTopShift();
refreshViewer();
}
}
}
int ListWidget::resizeGetHeight(int newWidth) { int ListWidget::resizeGetHeight(int newWidth) {
if (newWidth > 0) { if (newWidth > 0) {
for (auto &section : _sections) { for (auto &section : _sections) {
@ -887,7 +916,7 @@ int ListWidget::resizeGetHeight(int newWidth) {
return recountHeight(); return recountHeight();
} }
auto ListWidget::findItemByPoint(QPoint point) -> FoundItem { auto ListWidget::findItemByPoint(QPoint point) const -> FoundItem {
Expects(!_sections.empty()); Expects(!_sections.empty());
auto sectionIt = findSectionAfterTop(point.y()); auto sectionIt = findSectionAfterTop(point.y());
if (sectionIt == _sections.end()) { if (sectionIt == _sections.end()) {
@ -920,7 +949,7 @@ auto ListWidget::findItemDetails(
auto ListWidget::foundItemInSection( auto ListWidget::foundItemInSection(
const FoundItem &item, const FoundItem &item,
const Section &section) -> FoundItem { const Section &section) const -> FoundItem {
return { return {
item.layout, item.layout,
item.geometry.translated(0, section.top()), item.geometry.translated(0, section.top()),
@ -941,7 +970,7 @@ void ListWidget::checkMoveToOtherViewer() {
if (width() <= 0 if (width() <= 0
|| visibleHeight <= 0 || visibleHeight <= 0
|| _sections.empty() || _sections.empty()
|| _scrollTopId) { || _scrollTopState.item) {
return; return;
} }
@ -994,34 +1023,39 @@ void ListWidget::checkMoveToOtherViewer() {
} }
} }
void ListWidget::saveScrollState() { auto ListWidget::countScrollState() const -> ScrollTopState {
if (_sections.empty()) { if (_sections.empty()) {
_scrollTopId = 0; return { 0, 0 };
_scrollTopShift = 0;
return;
} }
auto topItem = findItemByPoint({ 0, _visibleTop }); auto topItem = findItemByPoint({ 0, _visibleTop });
_scrollTopId = GetUniversalId(topItem.layout); return {
_scrollTopShift = _visibleTop - topItem.geometry.y(); GetUniversalId(topItem.layout),
_visibleTop - topItem.geometry.y()
};
}
void ListWidget::saveScrollState() {
if (!_scrollTopState.item) {
_scrollTopState = countScrollState();
}
} }
void ListWidget::restoreScrollState() { void ListWidget::restoreScrollState() {
auto scrollTopId = base::take(_scrollTopId); if (_sections.empty() || !_scrollTopState.item) {
auto scrollTopShift = base::take(_scrollTopShift);
if (_sections.empty() || !scrollTopId) {
return; return;
} }
auto sectionIt = findSectionByItem(scrollTopId); auto sectionIt = findSectionByItem(_scrollTopState.item);
if (sectionIt == _sections.end()) { if (sectionIt == _sections.end()) {
--sectionIt; --sectionIt;
} }
auto item = foundItemInSection( auto item = foundItemInSection(
sectionIt->findItemNearId(scrollTopId), sectionIt->findItemNearId(_scrollTopState.item),
*sectionIt); *sectionIt);
auto newVisibleTop = item.geometry.y() + scrollTopShift; auto newVisibleTop = item.geometry.y() + _scrollTopState.shift;
if (_visibleTop != newVisibleTop) { if (_visibleTop != newVisibleTop) {
_scrollToRequests.fire_copy(newVisibleTop); _scrollToRequests.fire_copy(newVisibleTop);
} }
_scrollTopState = ScrollTopState();
} }
QMargins ListWidget::padding() const { QMargins ListWidget::padding() const {

View File

@ -74,6 +74,9 @@ public:
clearSelected(); clearSelected();
} }
void saveState(not_null<Memento*> memento);
void restoreState(not_null<Memento*> memento);
~ListWidget(); ~ListWidget();
protected: protected:
@ -150,6 +153,10 @@ private:
Touch, Touch,
Other, Other,
}; };
struct ScrollTopState {
UniversalMsgId item = 0;
int shift = 0;
};
void start(); void start();
int recountHeight(); int recountHeight();
@ -160,6 +167,7 @@ private:
bool isItemLayout( bool isItemLayout(
not_null<const HistoryItem*> item, not_null<const HistoryItem*> item,
BaseLayout *layout) const; BaseLayout *layout) const;
bool isPossiblyMyId(FullMsgId fullId) const;
void repaintItem(const HistoryItem *item); void repaintItem(const HistoryItem *item);
void repaintItem(UniversalMsgId msgId); void repaintItem(UniversalMsgId msgId);
void repaintItem(const BaseLayout *item); void repaintItem(const BaseLayout *item);
@ -229,13 +237,14 @@ private:
std::vector<Section>::const_iterator findSectionAfterBottom( std::vector<Section>::const_iterator findSectionAfterBottom(
std::vector<Section>::const_iterator from, std::vector<Section>::const_iterator from,
int bottom) const; int bottom) const;
FoundItem findItemByPoint(QPoint point); FoundItem findItemByPoint(QPoint point) const;
base::optional<FoundItem> findItemById(UniversalMsgId universalId); base::optional<FoundItem> findItemById(UniversalMsgId universalId);
base::optional<FoundItem> findItemDetails(BaseLayout *item); base::optional<FoundItem> findItemDetails(BaseLayout *item);
FoundItem foundItemInSection( FoundItem foundItemInSection(
const FoundItem &item, const FoundItem &item,
const Section &section); const Section &section) const;
ScrollTopState countScrollState() const;
void saveScrollState(); void saveScrollState();
void restoreScrollState(); void restoreScrollState();
@ -268,7 +277,8 @@ private:
Type _type = Type::Photo; Type _type = Type::Photo;
static constexpr auto kMinimalIdsLimit = 16; static constexpr auto kMinimalIdsLimit = 16;
UniversalMsgId _universalAroundId = (ServerMaxMsgId - 1); static constexpr auto kDefaultAroundId = (ServerMaxMsgId - 1);
UniversalMsgId _universalAroundId = kDefaultAroundId;
int _idsLimit = kMinimalIdsLimit; int _idsLimit = kMinimalIdsLimit;
SharedMediaMergedSlice _slice; SharedMediaMergedSlice _slice;
@ -277,8 +287,7 @@ private:
int _visibleTop = 0; int _visibleTop = 0;
int _visibleBottom = 0; int _visibleBottom = 0;
UniversalMsgId _scrollTopId = 0; ScrollTopState _scrollTopState;
int _scrollTopShift = 0;
rpl::event_stream<int> _scrollToRequests; rpl::event_stream<int> _scrollToRequests;
MouseAction _mouseAction = MouseAction::None; MouseAction _mouseAction = MouseAction::None;

View File

@ -104,7 +104,6 @@ void Widget::saveState(not_null<Memento*> memento) {
void Widget::restoreState(not_null<Memento*> memento) { void Widget::restoreState(not_null<Memento*> memento) {
_inner->restoreState(memento); _inner->restoreState(memento);
scrollTopRestore(memento->scrollTop());
} }
} // namespace Media } // namespace Media

View File

@ -52,8 +52,37 @@ public:
return _type; return _type;
} }
void setAroundId(FullMsgId aroundId) {
_aroundId = aroundId;
}
FullMsgId aroundId() const {
return _aroundId;
}
void setIdsLimit(int limit) {
_idsLimit = limit;
}
int idsLimit() const {
return _idsLimit;
}
void setScrollTopItem(FullMsgId item) {
_scrollTopItem = item;
}
FullMsgId scrollTopItem() const {
return _scrollTopItem;
}
void setScrollTopShift(int shift) {
_scrollTopShift = shift;
}
int scrollTopShift() const {
return _scrollTopShift;
}
private: private:
Type _type = Type::Photo; Type _type = Type::Photo;
FullMsgId _aroundId;
int _idsLimit = 0;
FullMsgId _scrollTopItem;
int _scrollTopShift = 0;;
}; };