diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index a295569910..6b5ee03337 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -7657,10 +7657,6 @@ void HistoryWidget::setupTranslateBar() { }, _translateBar->lifetime()); orderWidgets(); - - if (_showAnimation) { - _translateBar->hide(); - } } void HistoryWidget::setupPinnedTracker() { @@ -7803,10 +7799,6 @@ void HistoryWidget::checkPinnedBarState() { }, _pinnedBar->lifetime()); orderWidgets(); - - if (_showAnimation) { - _pinnedBar->hide(); - } } void HistoryWidget::clearHidingPinnedBar() { @@ -7966,10 +7958,6 @@ void HistoryWidget::setupGroupCallBar() { }, _groupCallBar->lifetime()); orderWidgets(); - - if (_showAnimation) { - _groupCallBar->hide(); - } } void HistoryWidget::setupRequestsBar() { @@ -8013,10 +8001,6 @@ void HistoryWidget::setupRequestsBar() { }, _requestsBar->lifetime()); orderWidgets(); - - if (_showAnimation) { - _requestsBar->hide(); - } } void HistoryWidget::requestMessageData(MsgId msgId) { diff --git a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp index 9d942cb026..a0b99c395c 100644 --- a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp +++ b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.cpp @@ -30,7 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace HistoryView { namespace { -constexpr auto kDefaultLimit = 10; +constexpr auto kDefaultLimit = 5;AssertIsDebug()// 10; } // namespace @@ -91,6 +91,54 @@ void SubsectionTabs::setupHorizontal(not_null parent) { } }, tabs->lifetime()); + scroll->setCustomWheelProcess([=](not_null e) { + const auto pixelDelta = e->pixelDelta(); + const auto angleDelta = e->angleDelta(); + if (std::abs(pixelDelta.x()) + std::abs(angleDelta.x())) { + return false; + } + const auto y = pixelDelta.y() ? pixelDelta.y() : angleDelta.y(); + scroll->scrollToX(scroll->scrollLeft() - y); + return true; + }); + + rpl::merge( + scroll->scrolls(), + _scrollCheckRequests.events(), + scroll->widthValue() | rpl::skip(1) | rpl::map_to(rpl::empty) + ) | rpl::start_with_next([=] { + const auto width = scroll->width(); + const auto left = scroll->scrollLeft(); + const auto max = scroll->scrollLeftMax(); + const auto availableLeft = left; + const auto availableRight = (max - left); + if (max <= 2 * width && _afterAvailable > 0) { + _beforeLimit *= 2; + _afterLimit *= 2; + } + if (availableLeft < width + && _beforeSkipped.value_or(0) > 0 + && !_slice.empty()) { + _around = _slice.front(); + refreshSlice(); + } else if (availableRight < width) { + if (_afterAvailable > 0) { + _around = _slice.back(); + refreshSlice(); + } else if (!_afterSkipped.has_value()) { + _loading = true; + loadMore(); + } + } + }, _horizontal->lifetime()); + + dataChanged() | rpl::start_with_next([=] { + if (_loading) { + _loading = false; + refreshSlice(); + } + }, _horizontal->lifetime()); + _horizontal->sizeValue( ) | rpl::start_with_next([=](QSize size) { const auto togglew = toggle->width(); @@ -127,14 +175,62 @@ void SubsectionTabs::setupHorizontal(not_null parent) { Ui::Text::WithEntities)); } } + const auto paused = [=] { + return _controller->isGifPausedAtLeastFor( + Window::GifPauseReason::Any); + }; + + auto scrollSavingThread = (Data::Thread*)nullptr; + auto scrollSavingShift = 0; + auto scrollSavingIndex = -1; + if (const auto count = tabs->sectionsCount()) { + const auto scrollLeft = scroll->scrollLeft(); + auto indexLeft = tabs->lookupSectionLeft(0); + for (auto index = 0; index != count; ++index) { + const auto nextLeft = (index + 1 != count) + ? tabs->lookupSectionLeft(index + 1) + : (indexLeft + scrollLeft + 1); + if (indexLeft <= scrollLeft && nextLeft > scrollLeft) { + scrollSavingThread = _sectionsSlice[index]; + scrollSavingShift = scrollLeft - indexLeft; + break; + } + indexLeft = nextLeft; + } + scrollSavingIndex = scrollSavingThread + ? int(ranges::find(_slice, not_null(scrollSavingThread)) + - begin(_slice)) + : -1; + if (scrollSavingIndex == _slice.size()) { + scrollSavingIndex = -1; + for (auto index = 0; index != count; ++index) { + const auto thread = _sectionsSlice[index]; + if (ranges::contains(_slice, thread)) { + scrollSavingThread = thread; + scrollSavingShift = scrollLeft + - tabs->lookupSectionLeft(index); + scrollSavingIndex = index; + break; + } + } + } + } + tabs->setSections(sections, Core::TextContext({ .session = &_history->session(), - })); + }), paused); tabs->fitWidthToSections(); tabs->setActiveSectionFast(activeIndex); + _sectionsSlice = _slice; _horizontal->resize( - tabs->width(), + _horizontal->width(), std::max(toggle->height(), tabs->height())); + if (scrollSavingIndex >= 0) { + scroll->scrollToX(tabs->lookupSectionLeft(scrollSavingIndex) + + scrollSavingShift); + } + + _scrollCheckRequests.fire({}); }, _horizontal->lifetime()); } @@ -179,6 +275,26 @@ void SubsectionTabs::setupVertical(not_null parent) { }, _vertical->lifetime()); } +void SubsectionTabs::loadMore() { + if (const auto forum = _history->peer->forum()) { + forum->requestTopics(); + } else if (const auto monoforum = _history->peer->monoforum()) { + monoforum->loadMore(); + } else { + Unexpected("Peer in SubsectionTabs::loadMore."); + } +} + +rpl::producer<> SubsectionTabs::dataChanged() const { + if (const auto forum = _history->peer->forum()) { + return forum->chatsListChanges(); + } else if (const auto monoforum = _history->peer->monoforum()) { + return monoforum->chatsListChanges(); + } else { + Unexpected("Peer in SubsectionTabs::dataChanged."); + } +} + void SubsectionTabs::toggleModes() { Expects((_horizontal || _vertical) && _shadow); @@ -323,6 +439,8 @@ void SubsectionTabs::refreshSlice() { }); if (!list) { slice.push_back(_history); + _beforeSkipped = _afterSkipped = 0; + _afterAvailable = 0; return; } const auto &chats = list->indexed()->all(); @@ -339,9 +457,8 @@ void SubsectionTabs::refreshSlice() { const auto from = i - takeBefore; const auto till = i + takeAfter; _beforeSkipped = std::max(0, int(from - chats.begin())); - _afterSkipped = list->loaded() - ? std::max(0, int(chats.end() - till)) - : std::optional(); + _afterAvailable = std::max(0, int(chats.end() - till)); + _afterSkipped = list->loaded() ? _afterAvailable : std::optional(); if (from == chats.begin()) { slice.push_back(_history); } @@ -358,6 +475,7 @@ bool SubsectionTabs::switchTo( if (thread->owningHistory() != _history) { return false; } + _active = thread; if (_vertical) { _vertical->setParent(parent); _vertical->show(); diff --git a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h index d896b1778c..fe5054dbe5 100644 --- a/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h +++ b/Telegram/SourceFiles/history/view/history_view_subsection_tabs.h @@ -57,6 +57,8 @@ private: void toggleModes(); void setVisible(bool shown); void refreshSlice(); + void loadMore(); + [[nodiscard]] rpl::producer<> dataChanged() const; const not_null _controller; const not_null _history; @@ -66,16 +68,20 @@ private: Ui::RpWidget *_shadow = nullptr; std::vector> _slice; + std::vector> _sectionsSlice; not_null _active; not_null _around; int _beforeLimit = 0; int _afterLimit = 0; + int _afterAvailable = 0; + bool _loading = false; std::optional _beforeSkipped; std::optional _afterSkipped; rpl::event_stream<> _layoutRequests; rpl::event_stream<> _refreshed; + rpl::event_stream<> _scrollCheckRequests; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp index d55da801d3..3c80be1720 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.cpp @@ -50,6 +50,7 @@ void DiscreteSlider::setActiveSectionFast(int index) { void DiscreteSlider::finishAnimating() { _a_left.stop(); + _a_width.stop(); update(); _callbackAfterMs = 0; if (_timerId >= 0) { @@ -64,10 +65,24 @@ void DiscreteSlider::setAdditionalContentWidthToSection(int index, int w) { } } +int DiscreteSlider::sectionsCount() const { + return int(_sections.size()); +} + +int DiscreteSlider::lookupSectionLeft(int index) const { + Expects(index >= 0 && index < _sections.size()); + + return _sections[index].left; +} + void DiscreteSlider::setSelectOnPress(bool selectOnPress) { _selectOnPress = selectOnPress; } +bool DiscreteSlider::paused() const { + return _paused && _paused(); +} + std::vector &DiscreteSlider::sectionsRef() { return _sections; } @@ -97,7 +112,8 @@ void DiscreteSlider::setSections(const std::vector &labels) { void DiscreteSlider::setSections( const std::vector &labels, - Text::MarkedContext context) { + Text::MarkedContext context, + Fn paused) { Assert(!labels.empty()); context.repaint = [this] { update(); }; @@ -106,6 +122,7 @@ void DiscreteSlider::setSections( for (const auto &label : labels) { _sections.push_back(Section(label, getLabelStyle(), context)); } + _paused = std::move(paused); refresh(); } @@ -122,7 +139,9 @@ void DiscreteSlider::refresh() { } DiscreteSlider::Range DiscreteSlider::getFinalActiveRange() const { - const auto raw = _sections.empty() ? nullptr : &_sections[_selected]; + const auto raw = (_sections.empty() || _selected < 0) + ? nullptr + : &_sections[_selected]; if (!raw) { return { 0, 0 }; } @@ -193,7 +212,7 @@ void DiscreteSlider::mouseReleaseEvent(QMouseEvent *e) { } void DiscreteSlider::setSelectedSection(int index) { - if (index < 0 || index >= _sections.size()) { + if (index >= int(_sections.size())) { return; } @@ -414,9 +433,10 @@ void SettingsSlider::paintEvent(QPaintEvent *e) { : section.width; const auto activeLeft = section.left + (section.width - activeWidth) / 2; + const auto divider = std::max(std::min(activeWidth, range.width), 1); const auto active = 1. - std::clamp( - std::abs(range.left - activeLeft) / float64(range.width), + std::abs(range.left - activeLeft) / float64(divider), 0., 1.); if (section.ripple) { @@ -467,6 +487,7 @@ void SettingsSlider::paintEvent(QPaintEvent *e) { .position = QPoint(labelLeft, _st.labelTop), .outerWidth = width(), .availableWidth = section.label.maxWidth(), + .paused = paused(), }); } return true; diff --git a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h index 4e9476bb02..6c7e6405bb 100644 --- a/Telegram/SourceFiles/ui/widgets/discrete_sliders.h +++ b/Telegram/SourceFiles/ui/widgets/discrete_sliders.h @@ -37,7 +37,8 @@ public: void setSections(const std::vector &labels); void setSections( const std::vector &labels, - Text::MarkedContext context = {}); + Text::MarkedContext context = {}, + Fn paused = nullptr); int activeSection() const { return _activeIndex; } @@ -51,6 +52,9 @@ public: return _sectionActivated.events(); } + [[nodiscard]] int sectionsCount() const; + [[nodiscard]] int lookupSectionLeft(int index) const; + protected: void timerEvent(QTimerEvent *e) override; void mousePressEvent(QMouseEvent *e) override; @@ -98,7 +102,9 @@ protected: void setSelectOnPress(bool selectOnPress); - std::vector
§ionsRef(); + [[nodiscard]] std::vector
§ionsRef(); + + [[nodiscard]] bool paused() const; private: void activateCallback(); @@ -109,6 +115,7 @@ private: void setSelectedSection(int index); std::vector
_sections; + Fn _paused; int _activeIndex = 0; bool _selectOnPress = true; bool _snapToLabel = false;