1
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-03-25 04:38:23 +00:00

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;
infoDesiredWidth: 360px;
infoDesiredWidth: 430px;
infoMinimalLayerMargin: 48px;
infoTabs: SettingsSlider(defaultTabsSlider) {

View File

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

View File

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

View File

@ -252,9 +252,11 @@ object_ptr<ListWidget> InnerWidget::setupList(
}
void InnerWidget::saveState(not_null<Memento*> memento) {
_list->saveState(memento);
}
void InnerWidget::restoreState(not_null<Memento*> memento) {
_list->restoreState(memento);
}
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());
}
bool ListWidget::isPossiblyMyId(FullMsgId fullId) const {
return (fullId.channel != 0)
? (_peer->isChannel() && _peer->bareId() == fullId.channel)
: (!_peer->isChannel() || _peer->migrateFrom());
}
bool ListWidget::isItemLayout(
not_null<const HistoryItem*> item,
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) {
if (newWidth > 0) {
for (auto &section : _sections) {
@ -887,7 +916,7 @@ int ListWidget::resizeGetHeight(int newWidth) {
return recountHeight();
}
auto ListWidget::findItemByPoint(QPoint point) -> FoundItem {
auto ListWidget::findItemByPoint(QPoint point) const -> FoundItem {
Expects(!_sections.empty());
auto sectionIt = findSectionAfterTop(point.y());
if (sectionIt == _sections.end()) {
@ -920,7 +949,7 @@ auto ListWidget::findItemDetails(
auto ListWidget::foundItemInSection(
const FoundItem &item,
const Section &section) -> FoundItem {
const Section &section) const -> FoundItem {
return {
item.layout,
item.geometry.translated(0, section.top()),
@ -941,7 +970,7 @@ void ListWidget::checkMoveToOtherViewer() {
if (width() <= 0
|| visibleHeight <= 0
|| _sections.empty()
|| _scrollTopId) {
|| _scrollTopState.item) {
return;
}
@ -994,34 +1023,39 @@ void ListWidget::checkMoveToOtherViewer() {
}
}
void ListWidget::saveScrollState() {
auto ListWidget::countScrollState() const -> ScrollTopState {
if (_sections.empty()) {
_scrollTopId = 0;
_scrollTopShift = 0;
return;
return { 0, 0 };
}
auto topItem = findItemByPoint({ 0, _visibleTop });
_scrollTopId = GetUniversalId(topItem.layout);
_scrollTopShift = _visibleTop - topItem.geometry.y();
return {
GetUniversalId(topItem.layout),
_visibleTop - topItem.geometry.y()
};
}
void ListWidget::saveScrollState() {
if (!_scrollTopState.item) {
_scrollTopState = countScrollState();
}
}
void ListWidget::restoreScrollState() {
auto scrollTopId = base::take(_scrollTopId);
auto scrollTopShift = base::take(_scrollTopShift);
if (_sections.empty() || !scrollTopId) {
if (_sections.empty() || !_scrollTopState.item) {
return;
}
auto sectionIt = findSectionByItem(scrollTopId);
auto sectionIt = findSectionByItem(_scrollTopState.item);
if (sectionIt == _sections.end()) {
--sectionIt;
}
auto item = foundItemInSection(
sectionIt->findItemNearId(scrollTopId),
sectionIt->findItemNearId(_scrollTopState.item),
*sectionIt);
auto newVisibleTop = item.geometry.y() + scrollTopShift;
auto newVisibleTop = item.geometry.y() + _scrollTopState.shift;
if (_visibleTop != newVisibleTop) {
_scrollToRequests.fire_copy(newVisibleTop);
}
_scrollTopState = ScrollTopState();
}
QMargins ListWidget::padding() const {

View File

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

View File

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

View File

@ -52,8 +52,37 @@ public:
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:
Type _type = Type::Photo;
FullMsgId _aroundId;
int _idsLimit = 0;
FullMsgId _scrollTopItem;
int _scrollTopShift = 0;;
};