// This is the source code of AyuGram for Desktop. // // We do not and cannot prevent the use of our code, // but be respectful and credit the original author. // // Copyright @Radolyn, 2024 #include "ayu/ui/sections/edited/edited_log_section.h" #include "apiwrap.h" #include "ayu/ui/sections/edited/edited_log_inner.h" #include "base/timer.h" #include "data/data_channel.h" #include "data/data_session.h" #include "lang/lang_keys.h" #include "profile/profile_back_button.h" #include "styles/style_chat.h" #include "styles/style_chat_helpers.h" #include "styles/style_info.h" #include "ui/ui_utility.h" #include "ui/boxes/confirm_box.h" #include "ui/widgets/buttons.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/shadow.h" #include "window/window_adaptive.h" #include "window/window_session_controller.h" #include "window/themes/window_theme.h" namespace EditedLog { class FixedBar final : public TWidget { public: FixedBar( QWidget *parent, not_null controller, not_null peer); // When animating mode is enabled the content is hidden and the // whole fixed bar acts like a back button. void setAnimatingMode(bool enabled); void goBack(); protected: void mousePressEvent(QMouseEvent *e) override; void paintEvent(QPaintEvent *e) override; int resizeGetHeight(int newWidth) override; private: not_null _controller; not_null _peer; object_ptr _backButton; object_ptr _cancel; bool _animatingMode = false; }; object_ptr SectionMemento::createWidget( QWidget *parent, not_null controller, Window::Column column, const QRect &geometry) { if (column == Window::Column::Third) { return nullptr; } auto result = object_ptr(parent, controller, _peer, _item); result->setInternalState(geometry, this); return result; } FixedBar::FixedBar( QWidget *parent, not_null controller, not_null peer) : TWidget(parent), _controller(controller), _peer(peer), _backButton( this, &controller->session(), tr::lng_terms_back(tr::now), controller->adaptive().oneColumnValue()), _cancel(this, st::historyAdminLogCancelSearch) { _backButton->moveToLeft(0, 0); _backButton->setClickedCallback([=] { goBack(); }); _cancel->hide(anim::type::instant); } void FixedBar::goBack() { _controller->showBackFromStack(); } int FixedBar::resizeGetHeight(int newWidth) { auto filterLeft = newWidth; auto cancelLeft = filterLeft - _cancel->width(); _cancel->moveToLeft(cancelLeft, 0); auto searchShownLeft = st::topBarArrowPadding.left(); auto searchHiddenLeft = filterLeft - 0; auto searchCurrentLeft = anim::interpolate(searchHiddenLeft, searchShownLeft, 0.0); _backButton->resizeToWidth(searchCurrentLeft); _backButton->moveToLeft(0, 0); auto newHeight = _backButton->height(); return newHeight; } void FixedBar::setAnimatingMode(bool enabled) { if (_animatingMode != enabled) { _animatingMode = enabled; setCursor(_animatingMode ? style::cur_pointer : style::cur_default); if (_animatingMode) { setAttribute(Qt::WA_OpaquePaintEvent, false); hideChildren(); } else { setAttribute(Qt::WA_OpaquePaintEvent); showChildren(); _cancel->setVisible(false); } show(); } } void FixedBar::paintEvent(QPaintEvent *e) { if (!_animatingMode) { auto p = QPainter(this); p.fillRect(e->rect(), st::topBarBg); } } void FixedBar::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { goBack(); } else { TWidget::mousePressEvent(e); } } Widget::Widget( QWidget *parent, not_null controller, not_null peer, not_null item) : Window::SectionWidget(parent, controller, rpl::single(peer)), _scroll(this, st::historyScroll, false), _fixedBar(this, controller, peer), _fixedBarShadow(this), _item(item) { _fixedBar->move(0, 0); _fixedBar->resizeToWidth(width()); _fixedBar->show(); _fixedBarShadow->raise(); controller->adaptive().value( ) | rpl::start_with_next([=] { updateAdaptiveLayout(); }, lifetime()); _inner = _scroll->setOwnedWidget(object_ptr(this, controller, peer, item)); _inner->scrollToSignal( ) | rpl::start_with_next([=](int top) { _scroll->scrollToY(top); }, lifetime()); _scroll->move(0, _fixedBar->height()); _scroll->show(); _scroll->scrolls( ) | rpl::start_with_next([=] { onScroll(); }, lifetime()); setupShortcuts(); } void Widget::updateAdaptiveLayout() { _fixedBarShadow->moveToLeft( controller()->adaptive().isOneColumn() ? 0 : st::lineWidth, _fixedBar->height()); } not_null Widget::channel() const { return _inner->channel(); } Dialogs::RowDescriptor Widget::activeChat() const { return { channel()->owner().history(channel()), FullMsgId(channel()->id, ShowAtUnreadMsgId) }; } QPixmap Widget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) { if (params.withTopBarShadow) _fixedBarShadow->hide(); auto result = Ui::GrabWidget(this); if (params.withTopBarShadow) _fixedBarShadow->show(); return result; } void Widget::doSetInnerFocus() { _inner->setFocus(); } bool Widget::showInternal( not_null memento, const Window::SectionShow ¶ms) { if (auto logMemento = dynamic_cast(memento.get())) { if (logMemento->getPeer() == channel()) { restoreState(logMemento); return true; } } return false; } void Widget::setInternalState(const QRect &geometry, not_null memento) { setGeometry(geometry); Ui::SendPendingMoveResizeEvents(this); restoreState(memento); } void Widget::setupShortcuts() { // todo: smth } std::shared_ptr Widget::createMemento() { auto result = std::make_shared(channel(), _item); saveState(result.get()); return result; } void Widget::saveState(not_null memento) { memento->setScrollTop(_scroll->scrollTop()); _inner->saveState(memento); } void Widget::restoreState(not_null memento) { _inner->restoreState(memento); auto scrollTop = memento->getScrollTop(); _scroll->scrollToY(scrollTop); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); } void Widget::resizeEvent(QResizeEvent *e) { if (!width() || !height()) { return; } auto contentWidth = width(); auto newScrollTop = _scroll->scrollTop() + topDelta(); _fixedBar->resizeToWidth(contentWidth); _fixedBarShadow->resize(contentWidth, st::lineWidth); auto bottom = height(); auto scrollHeight = bottom - _fixedBar->height(); auto scrollSize = QSize(contentWidth, scrollHeight); if (_scroll->size() != scrollSize) { _scroll->resize(scrollSize); _inner->resizeToWidth(scrollSize.width(), _scroll->height()); _inner->restoreScrollPosition(); } if (!_scroll->isHidden()) { if (topDelta()) { _scroll->scrollToY(newScrollTop); } auto scrollTop = _scroll->scrollTop(); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); } } void Widget::paintEvent(QPaintEvent *e) { if (animatingShow()) { SectionWidget::paintEvent(e); return; } else if (controller()->contentOverlapped(this, e)) { return; } //if (hasPendingResizedItems()) { // updateListSize(); //} //auto ms = crl::now(); //_historyDownShown.step(ms); const auto clip = e->rect(); SectionWidget::PaintBackground(controller(), _inner->theme(), this, clip); } void Widget::onScroll() { int scrollTop = _scroll->scrollTop(); _inner->setVisibleTopBottom(scrollTop, scrollTop + _scroll->height()); } void Widget::showAnimatedHook( const Window::SectionSlideParams ¶ms) { _fixedBar->setAnimatingMode(true); if (params.withTopBarShadow) _fixedBarShadow->show(); } void Widget::showFinishedHook() { _fixedBar->setAnimatingMode(false); } bool Widget::floatPlayerHandleWheelEvent(QEvent *e) { return _scroll->viewportEvent(e); } QRect Widget::floatPlayerAvailableRect() { return mapToGlobal(_scroll->geometry()); } } // namespace EditedLog