mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-17 22:57:11 +02:00
Fix scroll state management in Downloads.
This commit is contained in:
parent
bff8313a37
commit
a61048d219
19 changed files with 139 additions and 37 deletions
BIN
Telegram/Resources/icons/dialogs/dialogs_downloads.png
Normal file
BIN
Telegram/Resources/icons/dialogs/dialogs_downloads.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 390 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_downloads@2x.png
Normal file
BIN
Telegram/Resources/icons/dialogs/dialogs_downloads@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 696 B |
BIN
Telegram/Resources/icons/dialogs/dialogs_downloads@3x.png
Normal file
BIN
Telegram/Resources/icons/dialogs/dialogs_downloads@3x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1,020 B |
|
@ -878,14 +878,14 @@ SetupChannelBox::SetupChannelBox(
|
|||
(channel->isMegagroup()
|
||||
? tr::lng_create_public_group_about
|
||||
: tr::lng_create_public_channel_about)(tr::now),
|
||||
_defaultOptions,
|
||||
kDefaultTextOptions,
|
||||
_aboutPublicWidth)
|
||||
, _aboutPrivate(
|
||||
st::defaultTextStyle,
|
||||
(channel->isMegagroup()
|
||||
? tr::lng_create_private_group_about
|
||||
: tr::lng_create_private_channel_about)(tr::now),
|
||||
_defaultOptions,
|
||||
kDefaultTextOptions,
|
||||
_aboutPublicWidth)
|
||||
, _link(
|
||||
this,
|
||||
|
|
|
@ -327,4 +327,6 @@ downloadLoadingLeft: 15px;
|
|||
downloadLoadingSize: 24px;
|
||||
downloadLoadingLine: 2px;
|
||||
downloadLoadedSize: 30px;
|
||||
downloadIconDocument: icon {{ "history_file_document", windowFgActive }};
|
||||
downloadIconDocument: icon {{ "dialogs/dialogs_downloads", windowFgActive }};
|
||||
downloadIconSize: 16px;
|
||||
downloadIconSizeDone: 20px;
|
||||
|
|
|
@ -504,8 +504,6 @@ void InnerWidget::clearAndRequestLog() {
|
|||
}
|
||||
|
||||
void InnerWidget::updateEmptyText() {
|
||||
auto options = _defaultOptions;
|
||||
options.flags |= TextParseMarkdown;
|
||||
auto hasSearch = !_searchQuery.isEmpty();
|
||||
auto hasFilter = (_filter.flags != 0) || !_filter.allUsers;
|
||||
auto text = Ui::Text::Semibold((hasSearch || hasFilter)
|
||||
|
@ -522,7 +520,7 @@ void InnerWidget::updateEmptyText() {
|
|||
? tr::lng_admin_log_no_events_text(tr::now)
|
||||
: tr::lng_admin_log_no_events_text_channel(tr::now);
|
||||
text.text.append(qstr("\n\n") + description);
|
||||
_emptyText.setMarkedText(st::defaultTextStyle, text, options);
|
||||
_emptyText.setMarkedText(st::defaultTextStyle, text);
|
||||
}
|
||||
|
||||
QString InnerWidget::tooltipText() const {
|
||||
|
|
|
@ -524,7 +524,7 @@ ReplyKeyboard::ReplyKeyboard(
|
|||
button.text.setText(
|
||||
_st->textStyle(),
|
||||
TextUtilities::SingleLine(text),
|
||||
_textPlainOptions);
|
||||
kPlainTextOptions);
|
||||
button.characters = text.isEmpty() ? 1 : text.size();
|
||||
newRow.push_back(std::move(button));
|
||||
}
|
||||
|
|
|
@ -56,9 +56,7 @@ void EmptyListBubbleWidget::paintEvent(QPaintEvent *e) {
|
|||
|
||||
void EmptyListBubbleWidget::setText(
|
||||
const TextWithEntities &textWithEntities) {
|
||||
auto options = _defaultOptions;
|
||||
options.flags |= TextParseMarkdown;
|
||||
_text.setMarkedText(st::defaultTextStyle, textWithEntities, options);
|
||||
_text.setMarkedText(st::defaultTextStyle, textWithEntities);
|
||||
updateGeometry(size());
|
||||
}
|
||||
|
||||
|
|
|
@ -386,16 +386,49 @@ QString Provider::showInFolderPath(
|
|||
return (i != end(_elements)) ? i->path : QString();
|
||||
}
|
||||
|
||||
int64 Provider::scrollTopStatePosition(not_null<HistoryItem*> item) {
|
||||
const auto i = ranges::find(_elements, item, &Element::item);
|
||||
return (i != end(_elements)) ? i->started : 0;
|
||||
}
|
||||
|
||||
HistoryItem *Provider::scrollTopStateItem(ListScrollTopState state) {
|
||||
if (!state.position) {
|
||||
return _elements.empty() ? nullptr : _elements.back().item.get();
|
||||
}
|
||||
const auto i = ranges::lower_bound(
|
||||
_elements,
|
||||
state.position,
|
||||
ranges::less(),
|
||||
&Element::started);
|
||||
return (i != end(_elements))
|
||||
? i->item.get()
|
||||
: _elements.empty()
|
||||
? nullptr
|
||||
: _elements.back().item.get();
|
||||
}
|
||||
|
||||
void Provider::saveState(
|
||||
not_null<Media::Memento*> memento,
|
||||
ListScrollTopState scrollState) {
|
||||
|
||||
if (!_elements.empty() && scrollState.item) {
|
||||
memento->setAroundId({ PeerId(), 1 });
|
||||
memento->setScrollTopItem(scrollState.item->globalId());
|
||||
memento->setScrollTopItemPosition(scrollState.position);
|
||||
memento->setScrollTopShift(scrollState.shift);
|
||||
}
|
||||
}
|
||||
|
||||
void Provider::restoreState(
|
||||
not_null<Media::Memento*> memento,
|
||||
Fn<void(ListScrollTopState)> restoreScrollState) {
|
||||
|
||||
if (memento->aroundId() == FullMsgId(PeerId(), 1)) {
|
||||
restoreScrollState({
|
||||
.position = memento->scrollTopItemPosition(),
|
||||
.item = MessageByGlobalId(memento->scrollTopItem()),
|
||||
.shift = memento->scrollTopShift(),
|
||||
});
|
||||
refreshViewer();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Info::Downloads
|
||||
|
|
|
@ -70,6 +70,10 @@ public:
|
|||
not_null<const HistoryItem*> item,
|
||||
not_null<DocumentData*> document) override;
|
||||
|
||||
|
||||
int64 scrollTopStatePosition(not_null<HistoryItem*> item) override;
|
||||
HistoryItem *scrollTopStateItem(
|
||||
Media::ListScrollTopState state) override;
|
||||
void saveState(
|
||||
not_null<Media::Memento*> memento,
|
||||
Media::ListScrollTopState scrollState) override;
|
||||
|
|
|
@ -59,6 +59,7 @@ struct ListContext {
|
|||
};
|
||||
|
||||
struct ListScrollTopState {
|
||||
int64 position = 0; // ListProvider-specific.
|
||||
HistoryItem *item = nullptr;
|
||||
int shift = 0;
|
||||
};
|
||||
|
@ -157,6 +158,10 @@ public:
|
|||
not_null<const HistoryItem*> item,
|
||||
not_null<DocumentData*> document) = 0;
|
||||
|
||||
[[nodiscard]] virtual int64 scrollTopStatePosition(
|
||||
not_null<HistoryItem*> item) = 0;
|
||||
[[nodiscard]] virtual HistoryItem *scrollTopStateItem(
|
||||
ListScrollTopState state) = 0;
|
||||
virtual void saveState(
|
||||
not_null<Memento*> memento,
|
||||
ListScrollTopState scrollState) = 0;
|
||||
|
|
|
@ -163,7 +163,7 @@ void ListWidget::start() {
|
|||
if (_controller->isDownloads()) {
|
||||
_provider->refreshViewer();
|
||||
} else {
|
||||
subscribeToSession(&session(), lifetime());
|
||||
trackSession(&session());
|
||||
|
||||
_controller->mediaSourceQueryValue(
|
||||
) | rpl::start_with_next([this] {
|
||||
|
@ -482,6 +482,7 @@ bool ListWidget::preventAutoHide() const {
|
|||
|
||||
void ListWidget::saveState(not_null<Memento*> memento) {
|
||||
_provider->saveState(memento, countScrollState());
|
||||
_trackedSessions.clear();
|
||||
}
|
||||
|
||||
void ListWidget::restoreState(not_null<Memento*> memento) {
|
||||
|
@ -655,12 +656,14 @@ void ListWidget::clearHeavyItems() {
|
|||
}
|
||||
|
||||
ListScrollTopState ListWidget::countScrollState() const {
|
||||
if (_sections.empty()) {
|
||||
if (_sections.empty() || _visibleTop <= 0) {
|
||||
return {};
|
||||
}
|
||||
const auto topItem = findItemByPoint({ st::infoMediaSkip, _visibleTop });
|
||||
const auto item = topItem.layout->getItem();
|
||||
return {
|
||||
.item = topItem.layout->getItem(),
|
||||
.position = _provider->scrollTopStatePosition(item),
|
||||
.item = item,
|
||||
.shift = _visibleTop - topItem.geometry.y(),
|
||||
};
|
||||
}
|
||||
|
@ -672,16 +675,22 @@ void ListWidget::saveScrollState() {
|
|||
}
|
||||
|
||||
void ListWidget::restoreScrollState() {
|
||||
if (_sections.empty() || !_scrollTopState.item) {
|
||||
if (_sections.empty() || !_scrollTopState.position) {
|
||||
return;
|
||||
}
|
||||
_scrollTopState.item = _provider->scrollTopStateItem(_scrollTopState);
|
||||
if (!_scrollTopState.item) {
|
||||
return;
|
||||
}
|
||||
auto sectionIt = findSectionByItem(_scrollTopState.item);
|
||||
if (sectionIt == _sections.end()) {
|
||||
--sectionIt;
|
||||
}
|
||||
auto item = foundItemInSection( // #TODO downloads
|
||||
sectionIt->findItemNearId(GetUniversalId(_scrollTopState.item)),
|
||||
*sectionIt);
|
||||
const auto found = sectionIt->findItemByItem(_scrollTopState.item);
|
||||
if (!found) {
|
||||
return;
|
||||
}
|
||||
auto item = foundItemInSection(*found, *sectionIt);
|
||||
auto newVisibleTop = item.geometry.y() + _scrollTopState.shift;
|
||||
if (_visibleTop != newVisibleTop) {
|
||||
_scrollToRequests.fire_copy(newVisibleTop);
|
||||
|
@ -1080,7 +1089,9 @@ void ListWidget::deleteItems(SelectedItems &&items, Fn<void()> confirmed) {
|
|||
return item.globalId;
|
||||
}) | ranges::to_vector;
|
||||
Core::App().downloadManager().deleteFiles(ids);
|
||||
confirmed();
|
||||
if (confirmed) {
|
||||
confirmed();
|
||||
}
|
||||
};
|
||||
setActionBoxWeak(window->show(Box<Ui::ConfirmBox>(
|
||||
phrase,
|
||||
|
|
|
@ -511,6 +511,21 @@ void Provider::applyDragSelection(
|
|||
}
|
||||
}
|
||||
|
||||
int64 Provider::scrollTopStatePosition(not_null<HistoryItem*> item) {
|
||||
return GetUniversalId(item).bare;
|
||||
}
|
||||
|
||||
HistoryItem *Provider::scrollTopStateItem(ListScrollTopState state) {
|
||||
if (state.item && _slice.indexOf(state.item->fullId())) {
|
||||
return state.item;
|
||||
} else if (const auto id = _slice.nearest(state.position)) {
|
||||
if (const auto item = _controller->session().data().message(*id)) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return state.item;
|
||||
}
|
||||
|
||||
void Provider::saveState(
|
||||
not_null<Memento*> memento,
|
||||
ListScrollTopState scrollState) {
|
||||
|
@ -518,6 +533,7 @@ void Provider::saveState(
|
|||
memento->setAroundId(computeFullId(_universalAroundId));
|
||||
memento->setIdsLimit(_idsLimit);
|
||||
memento->setScrollTopItem(scrollState.item->globalId());
|
||||
memento->setScrollTopItemPosition(scrollState.position);
|
||||
memento->setScrollTopShift(scrollState.shift);
|
||||
}
|
||||
}
|
||||
|
@ -531,6 +547,7 @@ void Provider::restoreState(
|
|||
_idsLimit = limit;
|
||||
_universalAroundId = GetUniversalId(wasAroundId);
|
||||
restoreScrollState({
|
||||
.position = memento->scrollTopItemPosition(),
|
||||
.item = MessageByGlobalId(memento->scrollTopItem()),
|
||||
.shift = memento->scrollTopShift(),
|
||||
});
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
not_null<const HistoryItem*> item,
|
||||
not_null<DocumentData*> document) override;
|
||||
|
||||
int64 scrollTopStatePosition(not_null<HistoryItem*> item) override;
|
||||
HistoryItem *scrollTopStateItem(ListScrollTopState state) override;
|
||||
void saveState(
|
||||
not_null<Memento*> memento,
|
||||
ListScrollTopState scrollState) override;
|
||||
|
|
|
@ -34,9 +34,9 @@ public:
|
|||
not_null<Controller*> controller,
|
||||
const QRect &geometry) override;
|
||||
|
||||
Section section() const override;
|
||||
[[nodiscard]] Section section() const override;
|
||||
|
||||
Type type() const {
|
||||
[[nodiscard]] Type type() const {
|
||||
return _type;
|
||||
}
|
||||
|
||||
|
@ -44,32 +44,38 @@ public:
|
|||
void setAroundId(FullMsgId aroundId) {
|
||||
_aroundId = aroundId;
|
||||
}
|
||||
FullMsgId aroundId() const {
|
||||
[[nodiscard]] FullMsgId aroundId() const {
|
||||
return _aroundId;
|
||||
}
|
||||
void setIdsLimit(int limit) {
|
||||
_idsLimit = limit;
|
||||
}
|
||||
int idsLimit() const {
|
||||
[[nodiscard]] int idsLimit() const {
|
||||
return _idsLimit;
|
||||
}
|
||||
|
||||
void setScrollTopItem(GlobalMsgId item) {
|
||||
_scrollTopItem = item;
|
||||
}
|
||||
GlobalMsgId scrollTopItem() const {
|
||||
[[nodiscard]] GlobalMsgId scrollTopItem() const {
|
||||
return _scrollTopItem;
|
||||
}
|
||||
void setScrollTopItemPosition(int64 position) {
|
||||
_scrollTopItemPosition = position;
|
||||
}
|
||||
[[nodiscard]] int64 scrollTopItemPosition() const {
|
||||
return _scrollTopItemPosition;
|
||||
}
|
||||
void setScrollTopShift(int shift) {
|
||||
_scrollTopShift = shift;
|
||||
}
|
||||
int scrollTopShift() const {
|
||||
[[nodiscard]] int scrollTopShift() const {
|
||||
return _scrollTopShift;
|
||||
}
|
||||
void setSearchState(SearchState &&state) {
|
||||
_searchState = std::move(state);
|
||||
}
|
||||
SearchState searchState() {
|
||||
[[nodiscard]] SearchState searchState() {
|
||||
return std::move(_searchState);
|
||||
}
|
||||
|
||||
|
@ -77,6 +83,7 @@ private:
|
|||
Type _type = Type::Photo;
|
||||
FullMsgId _aroundId;
|
||||
int _idsLimit = 0;
|
||||
int64 _scrollTopItemPosition = 0;
|
||||
GlobalMsgId _scrollTopItem;
|
||||
int _scrollTopShift = 0;
|
||||
SearchState _searchState;
|
||||
|
|
|
@ -189,7 +189,7 @@ void ConfirmBox::init(const QString &text) {
|
|||
_text.setText(
|
||||
st::boxLabelStyle,
|
||||
text,
|
||||
_informative ? kInformBoxTextOptions : _textPlainOptions);
|
||||
_informative ? kInformBoxTextOptions : kPlainTextOptions);
|
||||
}
|
||||
|
||||
void ConfirmBox::init(const TextWithEntities &text) {
|
||||
|
|
|
@ -39,6 +39,12 @@ DownloadBar::DownloadBar(
|
|||
paint(p, clip);
|
||||
}, lifetime());
|
||||
|
||||
style::PaletteChanged(
|
||||
) | rpl::start_with_next([=] {
|
||||
refreshIcon();
|
||||
}, lifetime());
|
||||
refreshIcon();
|
||||
|
||||
_progress.value(
|
||||
) | rpl::start_with_next([=](const DownloadBarProgress &progress) {
|
||||
refreshInfo(progress);
|
||||
|
@ -56,7 +62,8 @@ void DownloadBar::show(DownloadBarContent &&content) {
|
|||
_radial.start(computeProgress());
|
||||
}
|
||||
_content = content;
|
||||
_title.setMarkedText(st::defaultTextStyle,
|
||||
_title.setMarkedText(
|
||||
st::defaultTextStyle,
|
||||
(content.count > 1
|
||||
? Ui::Text::Bold(
|
||||
tr::lng_profile_files(tr::now, lt_count, content.count))
|
||||
|
@ -64,8 +71,24 @@ void DownloadBar::show(DownloadBarContent &&content) {
|
|||
refreshInfo(_progress.current());
|
||||
}
|
||||
|
||||
void DownloadBar::refreshIcon() {
|
||||
_documentIconOriginal = st::downloadIconDocument.instance(
|
||||
st::windowFgActive->c,
|
||||
style::kScaleMax / style::DevicePixelRatio());
|
||||
const auto make = [&](int size) {
|
||||
auto result = _documentIconOriginal.scaledToWidth(
|
||||
size * style::DevicePixelRatio(),
|
||||
Qt::SmoothTransformation);
|
||||
result.setDevicePixelRatio(style::DevicePixelRatio());
|
||||
return result;
|
||||
};
|
||||
_documentIcon = make(st::downloadIconSize);
|
||||
_documentIconDone = make(st::downloadIconSizeDone);
|
||||
}
|
||||
|
||||
void DownloadBar::refreshInfo(const DownloadBarProgress &progress) {
|
||||
_info.setMarkedText(st::downloadInfoStyle,
|
||||
_info.setMarkedText(
|
||||
st::downloadInfoStyle,
|
||||
(progress.ready < progress.total
|
||||
? Text::WithEntities(
|
||||
FormatDownloadText(progress.ready, progress.total))
|
||||
|
@ -146,12 +169,10 @@ void DownloadBar::paint(Painter &p, QRect clip) {
|
|||
p.setOpacity(1.);
|
||||
}
|
||||
}
|
||||
p.save();
|
||||
p.translate(full.center());
|
||||
p.scale(0.6, 0.6);
|
||||
p.translate(-full.center());
|
||||
st::downloadIconDocument.paintInCenter(p, full);
|
||||
p.restore();
|
||||
p.drawImage(
|
||||
full.x() + (full.width() - st::downloadIconSize) / 2,
|
||||
full.y() + (full.height() - st::downloadIconSize) / 2,
|
||||
_documentIcon);
|
||||
}
|
||||
|
||||
const auto minleft = std::min(
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
|
||||
private:
|
||||
void paint(Painter &p, QRect clip);
|
||||
void refreshIcon();
|
||||
void refreshInfo(const DownloadBarProgress &progress);
|
||||
void radialAnimationCallback(crl::time now);
|
||||
[[nodiscard]] float64 computeProgress() const;
|
||||
|
@ -57,6 +58,9 @@ private:
|
|||
PlainShadow _shadow;
|
||||
DownloadBarContent _content;
|
||||
rpl::variable<DownloadBarProgress> _progress;
|
||||
QImage _documentIconOriginal;
|
||||
QImage _documentIcon;
|
||||
QImage _documentIconDone;
|
||||
Text::String _title;
|
||||
Text::String _info;
|
||||
RadialAnimation _radial;
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit bd7c4ee06d7292fddf5f4dbd2249efd4d7bc8e85
|
||||
Subproject commit 5214f96bbafa1d879fca39c3374cb182687084c8
|
Loading…
Add table
Reference in a new issue