diff --git a/Telegram/SourceFiles/api/api_chat_invite.cpp b/Telegram/SourceFiles/api/api_chat_invite.cpp index aa6534fd8..50bdaf4f0 100644 --- a/Telegram/SourceFiles/api/api_chat_invite.cpp +++ b/Telegram/SourceFiles/api/api_chat_invite.cpp @@ -116,14 +116,11 @@ void CheckChatInvite( } Core::App().hideMediaView(); const auto show = [&](not_null chat) { + const auto way = Window::SectionShow::Way::Forward; if (const auto forum = chat->forum()) { - strong->openForum( - forum->channel(), - Window::SectionShow::Way::Forward); + strong->showForum(forum, way); } else { - strong->showPeerHistory( - chat, - Window::SectionShow::Way::Forward); + strong->showPeerHistory(chat, way); } }; result.match([=](const MTPDchatInvite &data) { diff --git a/Telegram/SourceFiles/core/application.cpp b/Telegram/SourceFiles/core/application.cpp index 4719a6870..399196ef6 100644 --- a/Telegram/SourceFiles/core/application.cpp +++ b/Telegram/SourceFiles/core/application.cpp @@ -1241,8 +1241,10 @@ void Application::closeChatFromWindows(not_null peer) { PeerId(0), Window::SectionShow::Way::ClearStack); } - if (primary->openedForum().current() == peer) { - primary->closeForum(); + if (const auto forum = primary->shownForum().current()) { + if (peer->forum() == forum) { + primary->closeForum(); + } } } } diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 9a4dd7fe6..4b9b90c40 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -149,6 +149,9 @@ InnerWidget::InnerWidget( , _pinnedShiftAnimation([=](crl::time now) { return pinnedShiftAnimationCallback(now); }) +, _narrowWidth(st::defaultDialogRow.padding.left() + + st::defaultDialogRow.photoSize + + st::defaultDialogRow.padding.left()) , _cancelSearchInChat(this, st::dialogsCancelSearchInPeer) , _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer) { setAttribute(Qt::WA_OpaquePaintEvent, true); @@ -487,9 +490,8 @@ void InnerWidget::changeOpenedFolder(Data::Folder *folder) { } } -void InnerWidget::changeOpenedForum(ChannelData *forum) { - const auto now = _openedForum ? _openedForum->channel().get() : nullptr; - if (now == forum) { +void InnerWidget::changeOpenedForum(Data::Forum *forum) { + if (_openedForum == forum) { return; } stopReorderPinned(); @@ -501,19 +503,19 @@ void InnerWidget::changeOpenedForum(ChannelData *forum) { _filterId = forum ? 0 : _controller->activeChatsFilterCurrent(); - if (const auto old = now ? now->forum() : nullptr) { + if (_openedForum) { // If we close it inside forum destruction we should not schedule. - old->owner().forumIcons().scheduleUserpicsReset(old); + session().data().forumIcons().scheduleUserpicsReset(_openedForum); } - _openedForum = forum ? forum->forum() : nullptr; + _openedForum = forum; _st = forum ? &st::forumTopicRow : &st::defaultDialogRow; refreshShownList(); _openedForumLifetime.destroy(); if (forum) { rpl::merge( - forum->forum()->chatsListChanges(), - forum->forum()->chatsListLoadedEvents() + forum->chatsListChanges(), + forum->chatsListLoadedEvents() ) | rpl::start_with_next([=] { refresh(); }, _openedForumLifetime); @@ -571,7 +573,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { && _selectedTopicJump && (!_pressed || _pressedTopicJump)), .paused = videoPaused, - .narrow = (fullWidth < st::columnMinimalWidthLeft), + .narrow = (fullWidth < st::columnMinimalWidthLeft / 2), }); }; if (_state == WidgetState::Default) { @@ -826,7 +828,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { .selected = selected, .paused = videoPaused, .search = true, - .narrow = (fullWidth < st::columnMinimalWidthLeft), + .narrow = (fullWidth < st::columnMinimalWidthLeft / 2), .displayUnreadInfo = showUnreadInSearchResults, }); p.translate(0, _st->height); @@ -896,7 +898,7 @@ void InnerWidget::paintCollapsedRow( .st = _st, .width = fullWidth, .selected = selected, - .narrow = (fullWidth < st::columnMinimalWidthLeft), + .narrow = (fullWidth < st::columnMinimalWidthLeft / 2), }); } @@ -1698,7 +1700,9 @@ void InnerWidget::resizeEvent(QResizeEvent *e) { } void InnerWidget::moveCancelSearchButtons() { - const auto widthForCancelButton = qMax(width(), st::columnMinimalWidthLeft); + const auto widthForCancelButton = qMax( + width(), + st::columnMinimalWidthLeft - _narrowWidth); const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width(); const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2; _cancelSearchInChat->moveToLeft(left, st::searchedBarHeight + top); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 8265b3101..8001b5404 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -102,7 +102,7 @@ public: void clearSelection(); void changeOpenedFolder(Data::Folder *folder); - void changeOpenedForum(ChannelData *forum); + void changeOpenedForum(Data::Forum *forum); void selectSkip(int32 direction); void selectSkipPage(int32 pixels, int32 direction); @@ -422,6 +422,7 @@ private: // Remember the last currently dragged row top shift for updating area. int _aboveTopShift = -1; + int _narrowWidth = 0; int _visibleTop = 0; int _visibleBottom = 0; diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 3bfe85d80..9f7e57cf4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -178,10 +178,15 @@ void Widget::BottomButton::paintEvent(QPaintEvent *e) { Widget::Widget( QWidget *parent, - not_null controller) + not_null controller, + Layout layout) : Window::AbstractSectionWidget(parent, controller, nullptr) , _api(&controller->session().mtp()) , _chooseByDragTimer([=] { _inner->chooseRow(); }) +, _layout(layout) +, _narrowWidth(st::defaultDialogRow.padding.left() + + st::defaultDialogRow.photoSize + + st::defaultDialogRow.padding.left()) , _searchControls(this) , _mainMenuToggle(_searchControls, st::dialogsMenuToggle) , _searchForNarrowFilters(_searchControls, st::dialogsSearchForNarrowFilters) @@ -216,7 +221,7 @@ Widget::Widget( Data::HistoryUpdate::Flag::MessageSent ) | rpl::filter([=](const Data::HistoryUpdate &update) { if (_openedForum) { - return (update.history->peer == _openedForum); + return (update.history == _openedForum->history()); } else if (_openedFolder) { return (update.history->folder() == _openedFolder) && !update.history->isPinnedDialog(FilterId()); @@ -273,7 +278,7 @@ Widget::Widget( _inner->cancelSearchFromUserRequests( ) | rpl::start_with_next([=] { setSearchInChat((_openedForum && !_searchInChat) - ? Key(_openedForum->forum()->history()) + ? Key(_openedForum->history()) : _searchInChat, nullptr); applyFilterUpdate(true); }, lifetime()); @@ -346,7 +351,10 @@ Widget::Widget( setupShortcuts(); _searchForNarrowFilters->setClickedCallback([=] { - Ui::showChatsList(&session()); + if (_childList) { + controller->closeForum(); + } + _filter->setFocus(); }); setAcceptDrops(true); @@ -368,7 +376,7 @@ Widget::Widget( && !_searchFullMigrated))) { searchMore(); } else if (_openedForum && state == WidgetState::Default) { - _openedForum->forum()->requestTopics(); + _openedForum->requestTopics(); } else { const auto folder = _inner->shownFolder(); if (!folder || !folder->chatsList()->loaded()) { @@ -399,14 +407,19 @@ Widget::Widget( changeOpenedFolder(folder, anim::type::normal); }, lifetime()); - changeOpenedForum( - controller->openedForum().current(), - anim::type::instant); - - controller->openedForum().changes( - ) | rpl::start_with_next([=](ChannelData *forum) { - changeOpenedForum(forum, anim::type::normal); - }, lifetime()); + if (_layout != Layout::Child) { + controller->shownForum().changes( + ) | rpl::filter(!rpl::mappers::_1) | rpl::start_with_next([=] { + if (_openedForum) { + changeOpenedForum(nullptr, anim::type::normal); + } else if (_childList) { + _childList = nullptr; + _childListShadow = nullptr; + updateControlsGeometry(); + updateControlsVisibility(true); + } + }, lifetime()); + } setupDownloadBar(); } @@ -420,7 +433,9 @@ void Widget::chosenRow(const ChosenRow &row) { : nullptr; if (topicJump) { if (!controller()->adaptive().isOneColumn()) { - controller()->openForum(history->peer->asChannel()); + controller()->showForum( + topicJump->forum(), + Window::SectionShow().withChildColumn()); } controller()->content()->chooseThread( topicJump, @@ -431,7 +446,9 @@ void Widget::chosenRow(const ChosenRow &row) { topic, row.message.fullId.msg); } else if (history && history->peer->isForum() && !row.message.fullId) { - controller()->openForum(history->peer->asChannel()); + controller()->showForum( + history->peer->forum(), + Window::SectionShow().withChildColumn()); return; } else if (history) { const auto peer = history->peer; @@ -450,19 +467,18 @@ void Widget::chosenRow(const ChosenRow &row) { }; if (fromActive) { controller()->window().preventOrInvoke([=] { - controller()->content()->ui_showPeerHistory( - 0, - Window::SectionShow::Way::ClearStack, - 0); + controller()->clearSectionStack(); toSeparate(); }); } else { toSeparate(); } } else { + hideChildList(); controller()->content()->chooseThread(history, showAtMsgId); } } else if (const auto folder = row.key.folder()) { + hideChildList(); controller()->openFolder(folder); } if (openSearchResult && !session().supportMode()) { @@ -576,7 +592,8 @@ void Widget::updateScrollUpVisibility() { } void Widget::startScrollUpButtonAnimation(bool shown) { - const auto smallColumn = (width() < st::columnMinimalWidthLeft); + const auto smallColumn = (width() < st::columnMinimalWidthLeft) + || _childList; shown &= !smallColumn; if (_scrollToTopIsShown == shown) { return; @@ -659,7 +676,7 @@ void Widget::setupShortcuts() { } if (_openedForum && !controller()->activeChatCurrent()) { request->check(Command::Search) && request->handle([=] { - const auto history = _openedForum->forum()->history(); + const auto history = _openedForum->history(); controller()->content()->searchInChat(history); return true; }); @@ -723,6 +740,10 @@ void Widget::updateControlsVisibility(bool fast) { updateSearchFromVisibility(fast); } _connecting->setForceHidden(false); + if (_childList) { + _childList->show(); + _childListShadow->show(); + } } void Widget::changeOpenedSubsection( @@ -761,7 +782,7 @@ void Widget::changeOpenedFolder(Data::Folder *folder, anim::type animated) { }, (folder != nullptr), animated); } -void Widget::changeOpenedForum(ChannelData *forum, anim::type animated) { +void Widget::changeOpenedForum(Data::Forum *forum, anim::type animated) { changeOpenedSubsection([&] { cancelSearch(); _openedForum = forum; @@ -770,6 +791,12 @@ void Widget::changeOpenedForum(ChannelData *forum, anim::type animated) { }, (forum != nullptr), animated); } +void Widget::hideChildList() { + if (_childList) { + controller()->closeForum(); + } +} + void Widget::refreshTopBars() { if (_openedFolder || _openedForum) { if (!_subsectionTopBar) { @@ -797,7 +824,7 @@ void Widget::refreshTopBars() { updateControlsGeometry(); } const auto history = _openedForum - ? session().data().history(_openedForum).get() + ? _openedForum->history().get() : nullptr; _subsectionTopBar->setActiveChat( HistoryView::TopBarWidget::ActiveChat{ @@ -817,23 +844,24 @@ void Widget::refreshTopBars() { } _forumSearchRequested = false; if (_openedForum) { - _openedForum->updateFull(); + const auto channel = _openedForum->channel(); + channel->updateFull(); _forumReportBar = std::make_unique( controller(), this, - _openedForum, + channel, true); _forumRequestsBar = std::make_unique( this, HistoryView::RequestsBarContentByPeer( - _openedForum, + channel, st::historyRequestsUserpics.size, true)); _forumGroupCallBar = std::make_unique( this, HistoryView::GroupCallBarContentByPeer( - _openedForum, + channel, st::historyGroupCallUserpics.size, true), Core::App().appDeactivatedValue()); @@ -841,15 +869,15 @@ void Widget::refreshTopBars() { _forumRequestsBar->barClicks( ) | rpl::start_with_next([=] { - RequestsBoxController::Start(controller(), _openedForum); + RequestsBoxController::Start(controller(), channel); }, _forumRequestsBar->lifetime()); rpl::merge( _forumGroupCallBar->barClicks(), _forumGroupCallBar->joinClicks() ) | rpl::start_with_next([=] { - if (_openedForum->groupCall()) { - controller()->startOrJoinGroupCall(_openedForum); + if (channel->groupCall()) { + controller()->startOrJoinGroupCall(channel); } }, _forumGroupCallBar->lifetime()); @@ -959,7 +987,7 @@ void Widget::jumpToTop(bool belowPinned) { auto to = 0; if (belowPinned) { const auto list = _openedForum - ? _openedForum->forum()->topicsList() + ? _openedForum->topicsList() : controller()->activeChatsFilterCurrent() ? session().data().chatsFilters().chatsList( controller()->activeChatsFilterCurrent()) @@ -1113,7 +1141,7 @@ void Widget::animationCallback() { void Widget::escape() { if (!cancelSearch()) { - if (controller()->openedForum().current()) { + if (controller()->shownForum().current()) { controller()->closeForum(); } else if (controller()->openedFolder().current()) { controller()->closeFolder(); @@ -1351,7 +1379,7 @@ bool Widget::searchForTopicsRequired(const QString &query) const { && _openedForum && !query.isEmpty() && (query[0] != '#') - && !_openedForum->forum()->topicsList()->loaded(); + && !_openedForum->topicsList()->loaded(); } void Widget::needSearchMessages() { @@ -1370,7 +1398,7 @@ void Widget::searchMessages( const auto inChatChanged = [&] { const auto inPeer = inChat.peer(); const auto inTopic = inChat.topic(); - if (!inTopic && inPeer == _openedForum) { + if (!inTopic && _openedForum && inPeer == _openedForum->channel()) { return false; } else if ((inTopic || (inPeer && !inPeer->isForum())) && (inChat == _searchInChat)) { @@ -1404,7 +1432,7 @@ void Widget::searchTopics() { _api.request(base::take(_topicSearchRequest)).cancel(); _topicSearchRequest = _api.request(MTPchannels_GetForumTopics( MTP_flags(MTPchannels_GetForumTopics::Flag::f_q), - _openedForum->inputChannel, + _openedForum->channel()->inputChannel, MTP_string(_topicSearchQuery), MTP_int(_topicSearchOffsetDate), MTP_int(_topicSearchOffsetId), @@ -1414,7 +1442,7 @@ void Widget::searchTopics() { _topicSearchRequest = 0; const auto savedTopicId = _topicSearchOffsetTopicId; const auto byCreation = result.data().is_order_by_create_date(); - _openedForum->forum()->applyReceivedTopics(result, [&]( + _openedForum->applyReceivedTopics(result, [&]( not_null topic) { _topicSearchOffsetTopicId = topic->rootId(); if (byCreation) { @@ -1826,6 +1854,9 @@ void Widget::dropEvent(QDropEvent *e) { const auto point = mapToGlobal(e->pos()); if (const auto thread = _inner->updateFromParentDrag(point)) { e->acceptProposedAction(); + if (!thread->owningHistory()->peer->isForum()) { + hideChildList(); + } controller()->content()->onFilesOrForwardDrop( thread, e->mimeData()); @@ -1877,6 +1908,39 @@ void Widget::applyFilterUpdate(bool force) { _lastFilterText = filterText; } +void Widget::showForum( + not_null forum, + const Window::SectionShow ¶ms) { + if (!params.childColumn + || !Core::App().settings().dialogsWidthRatio() + || (_layout != Layout::Main)) { + changeOpenedForum(forum, params.animated); + return; + } + cancelSearch(); + auto copy = params; + copy.childColumn = false; + copy.animated = anim::type::instant; + _childList = std::make_unique( + this, + controller(), + Layout::Child); + _childList->showForum(forum, copy); + _childListShadow = std::make_unique(this); + _childListShadow->setAttribute(Qt::WA_TransparentForMouseEvents); + _childListShadow->paintRequest( + ) | rpl::start_with_next([=] { + auto p = QPainter(_childListShadow.get()); + st::slideShadow.fill(p, QRect( + _childListShadow->width() - st::slideShadow.width(), + 0, + st::slideShadow.width(), + _childListShadow->height())); + }, _childListShadow->lifetime()); + updateControlsGeometry(); + updateControlsVisibility(true); +} + void Widget::searchInChat(Key chat) { if (_openedForum && !chat.peer()->forum()) { controller()->closeForum(); @@ -1889,7 +1953,13 @@ void Widget::searchInChat(Key chat) { applyFilterUpdate(true); } -void Widget::setSearchInChat(Key chat, PeerData *from) { +bool Widget::setSearchInChat(Key chat, PeerData *from) { + if (_childList) { + if (_childList->setSearchInChat(chat, from)) { + return true; + } + hideChildList(); + } const auto peer = chat.peer(); const auto topic = chat.topic(); const auto forum = peer ? peer->forum() : nullptr; @@ -1907,11 +1977,13 @@ void Widget::setSearchInChat(Key chat, PeerData *from) { _searchFromAuthor = from; if (forum) { - if (controller()->openedForum().current() == peer) { + if (_openedForum == forum) { showSearchInTopBar(anim::type::normal); - } else { + } else if (_layout == Layout::Main) { _forumSearchRequested = true; - controller()->openForum(forum->channel()); + controller()->showForum(forum); + } else { + return false; } } _searchInMigrated = nullptr; @@ -1943,6 +2015,7 @@ void Widget::setSearchInChat(Key chat, PeerData *from) { cancelSearch(); } _filter->setFocus(); + return true; } void Widget::clearSearchCache() { @@ -1971,7 +2044,7 @@ void Widget::showSearchFrom() { if (const auto peer = searchInPeer()) { const auto weak = base::make_weak(_searchInChat.topic()); const auto chat = (!_searchInChat && _openedForum) - ? Key(_openedForum->forum()->history()) + ? Key(_openedForum->history()) : _searchInChat; auto box = SearchFromBox( peer, @@ -2107,25 +2180,37 @@ void Widget::updateControlsGeometry() { _forwardCancel->moveToLeft(0, filterAreaTop); filterAreaTop += st::dialogsForwardHeight; } - auto smallLayoutWidth = (st::defaultDialogRow.padding.left() + st::defaultDialogRow.photoSize + st::defaultDialogRow.padding.left()); - auto smallLayoutRatio = (width() < st::columnMinimalWidthLeft) ? (st::columnMinimalWidthLeft - width()) / float64(st::columnMinimalWidthLeft - smallLayoutWidth) : 0.; - auto filterLeft = (controller()->filtersWidth() ? st::dialogsFilterSkip : st::dialogsFilterPadding.x() + _mainMenuToggle->width()) + st::dialogsFilterPadding.x(); - auto filterRight = (session().domain().local().hasLocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x(); - auto filterWidth = qMax(width(), st::columnMinimalWidthLeft) - filterLeft - filterRight; + const auto usew = _childList ? _narrowWidth : width(); + const auto childw = std::max(_narrowWidth, width() - usew); + const auto smallw = st::columnMinimalWidthLeft - _narrowWidth; + const auto smallLayoutRatio = (usew < smallw) + ? ((smallw - usew) / float64(smallw - _narrowWidth)) + : 0.; + auto filterLeft = (controller()->filtersWidth() + ? st::dialogsFilterSkip + : (st::dialogsFilterPadding.x() + _mainMenuToggle->width())) + + st::dialogsFilterPadding.x(); + auto filterRight = (session().domain().local().hasLocalPasscode() + ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) + : st::dialogsFilterSkip) + st::dialogsFilterPadding.x(); + auto filterWidth = qMax(usew, smallw) - filterLeft - filterRight; auto filterAreaHeight = st::topBarHeight; - _searchControls->setGeometry(0, filterAreaTop, width(), filterAreaHeight); + _searchControls->setGeometry(0, filterAreaTop, usew, filterAreaHeight); if (_subsectionTopBar) { _subsectionTopBar->setGeometry(_searchControls->geometry()); } auto filterTop = (filterAreaHeight - _filter->height()) / 2; - filterLeft = anim::interpolate(filterLeft, smallLayoutWidth, smallLayoutRatio); + filterLeft = anim::interpolate(filterLeft, _narrowWidth, smallLayoutRatio); _filter->setGeometryToLeft(filterLeft, filterTop, filterWidth, _filter->height()); - auto mainMenuLeft = anim::interpolate(st::dialogsFilterPadding.x(), (smallLayoutWidth - _mainMenuToggle->width()) / 2, smallLayoutRatio); + auto mainMenuLeft = anim::interpolate( + st::dialogsFilterPadding.x(), + (_narrowWidth - _mainMenuToggle->width()) / 2, + smallLayoutRatio); _mainMenuToggle->moveToLeft(mainMenuLeft, st::dialogsFilterPadding.y()); const auto searchLeft = anim::interpolate( -_searchForNarrowFilters->width(), - (smallLayoutWidth - _searchForNarrowFilters->width()) / 2, + (_narrowWidth - _searchForNarrowFilters->width()) / 2, smallLayoutRatio); _searchForNarrowFilters->moveToLeft(searchLeft, st::dialogsFilterPadding.y()); @@ -2139,19 +2224,19 @@ void Widget::updateControlsGeometry() { _forumTopShadow->setGeometry( 0, filterAreaTop + filterAreaHeight, - width(), + usew, st::lineWidth); } const auto forumGroupCallTop = filterAreaTop + filterAreaHeight; if (_forumGroupCallBar) { _forumGroupCallBar->move(0, forumGroupCallTop); - _forumGroupCallBar->resizeToWidth(width()); + _forumGroupCallBar->resizeToWidth(usew); } const auto forumRequestsTop = forumGroupCallTop + (_forumGroupCallBar ? _forumGroupCallBar->height() : 0); if (_forumRequestsBar) { _forumRequestsBar->move(0, forumRequestsTop); - _forumRequestsBar->resizeToWidth(width()); + _forumRequestsBar->resizeToWidth(usew); } const auto forumReportTop = forumRequestsTop + (_forumRequestsBar ? _forumRequestsBar->height() : 0); @@ -2169,7 +2254,7 @@ void Widget::updateControlsGeometry() { button->setGeometry( 0, scrollTop + scrollHeight, - width(), + usew, buttonHeight); } }; @@ -2182,8 +2267,8 @@ void Widget::updateControlsGeometry() { } controller()->setConnectingBottomSkip(bottomSkip); auto wasScrollHeight = _scroll->height(); - _scroll->setGeometry(0, scrollTop, width(), scrollHeight); - _inner->resize(width(), _inner->height()); + _scroll->setGeometry(0, scrollTop, usew, scrollHeight); + _inner->resize(usew, _inner->height()); if (scrollHeight != wasScrollHeight) { controller()->floatPlayerAreaUpdated(); } @@ -2195,6 +2280,13 @@ void Widget::updateControlsGeometry() { if (_scrollToTopIsShown) { updateScrollUpPosition(); } + + if (_childList) { + _childList->setGeometryWithTopMoved( + { width() - childw, 0, childw, height() }, + _topDelta); + _childListShadow->setGeometry(0, 0, (width() - childw), height()); + } } rpl::producer<> Widget::closeForwardBarRequests() const { @@ -2322,7 +2414,9 @@ void Widget::cancelSearchRequest() { } PeerData *Widget::searchInPeer() const { - return _openedForum ? _openedForum : _searchInChat.peer(); + return _openedForum + ? _openedForum->channel().get() + : _searchInChat.peer(); } Data::ForumTopic *Widget::searchInTopic() const { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index e92338bcd..f51ceb9c5 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -20,6 +20,10 @@ namespace MTP { class Error; } // namespace MTP +namespace Data { +class Forum; +} // namespace Data + namespace Main { class Session; } // namespace Main @@ -47,6 +51,7 @@ class FadeWrapScaled; namespace Window { class SessionController; class ConnectionState; +struct SectionShow; } // namespace Window namespace Dialogs { @@ -61,7 +66,14 @@ enum class SearchRequestType; class Widget final : public Window::AbstractSectionWidget { public: - Widget(QWidget *parent, not_null controller); + enum class Layout { + Main, + Child, + }; + Widget( + QWidget *parent, + not_null controller, + Layout layout); // When resizing the widget with top edge moved up or down and we // want to add this top movement to the scroll position, so inner @@ -70,6 +82,9 @@ public: void updateDragInScroll(bool inScroll); + void showForum( + not_null forum, + const Window::SectionShow ¶ms); void searchInChat(Key chat); void setInnerFocus(); @@ -81,7 +96,9 @@ public: bool hasTopBarShadow() const { return true; } - void showAnimated(Window::SlideDirection direction, const Window::SectionSlideParams ¶ms); + void showAnimated( + Window::SlideDirection direction, + const Window::SectionSlideParams ¶ms); void showFast(); void scrollToEntry(const RowDescriptor &entry); @@ -152,7 +169,7 @@ private: void setupShortcuts(); [[nodiscard]] bool searchForPeersRequired(const QString &query) const; [[nodiscard]] bool searchForTopicsRequired(const QString &query) const; - void setSearchInChat(Key chat, PeerData *from = nullptr); + bool setSearchInChat(Key chat, PeerData *from = nullptr); void showCalendar(); void showSearchFrom(); void showMainMenu(); @@ -171,8 +188,9 @@ private: bool fromRight, anim::type animated); void changeOpenedFolder(Data::Folder *folder, anim::type animated); - void changeOpenedForum(ChannelData *forum, anim::type animated); - QPixmap grabForFolderSlideAnimation(); + void changeOpenedForum(Data::Forum *forum, anim::type animated); + void hideChildList(); + [[nodiscard]] QPixmap grabForFolderSlideAnimation(); void startSlideAnimation(); void fullSearchRefreshOn(rpl::producer<> events); @@ -198,6 +216,8 @@ private: bool _dragForward = false; base::Timer _chooseByDragTimer; + Layout _layout = Layout::Main; + int _narrowWidth = 0; object_ptr _forwardCancel = { nullptr }; object_ptr _searchControls; object_ptr _subsectionTopBar = { nullptr } ; @@ -234,7 +254,7 @@ private: bool _forumSearchRequested = false; Data::Folder *_openedFolder = nullptr; - ChannelData *_openedForum = nullptr; + Data::Forum *_openedForum = nullptr; Dialogs::Key _searchInChat; History *_searchInMigrated = nullptr; PeerData *_searchFromAuthor = nullptr; @@ -277,6 +297,9 @@ private: rpl::event_stream<> _closeForwardBarRequests; + std::unique_ptr _childList; + std::unique_ptr _childListShadow; + }; } // namespace Dialogs diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 21b7c13c4..5c3b43915 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -35,46 +35,27 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_session.h" #include "styles/style_chat.h" -namespace { - -[[nodiscard]] MainWidget *CheckMainWidget(not_null session) { - if (const auto m = App::main()) { // multi good - if (&m->session() == session) { - return m; - } - } - if (&Core::App().domain().active() != &session->account()) { - Core::App().domain().activate(&session->account()); - } - if (const auto m = App::main()) { // multi good - if (&m->session() == session) { - return m; - } - } - return nullptr; -} - -} // namespace - namespace Ui { void showChatsList(not_null session) { - if (const auto m = CheckMainWidget(session)) { - m->ui_showPeerHistory( - 0, - ::Window::SectionShow::Way::ClearStack, - 0); + if (const auto window = session->tryResolveWindow()) { + window->clearSectionStack(); } } -void showPeerHistory(not_null history, MsgId msgId) { - showPeerHistory(history->peer, msgId); +void showPeerHistory(not_null history, MsgId msgId) { + if (const auto window = history->session().tryResolveWindow()) { + window->showPeerHistory( + history, + ::Window::SectionShow::Way::ClearStack, + msgId); + } } -void showPeerHistory(not_null peer, MsgId msgId) { - if (const auto m = CheckMainWidget(&peer->session())) { - m->ui_showPeerHistory( - peer->id, +void showPeerHistory(not_null peer, MsgId msgId) { + if (const auto window = peer->session().tryResolveWindow()) { + window->showPeerHistory( + peer, ::Window::SectionShow::Way::ClearStack, msgId); } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 10c0e7fb4..1dee53a40 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -40,8 +40,8 @@ namespace Ui { // Legacy global methods. -void showPeerHistory(not_null peer, MsgId msgId); -void showPeerHistory(not_null history, MsgId msgId); +void showPeerHistory(not_null peer, MsgId msgId); +void showPeerHistory(not_null history, MsgId msgId); void showChatsList(not_null session); bool skipPaintEvent(QWidget *widget, QPaintEvent *event); diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index 35f69c44c..51f2c5ab4 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -633,16 +633,16 @@ Ui::MultiSlideTracker DetailsFiller::fillTopicButtons() { Ui::MultiSlideTracker tracker; const auto window = _controller->parentController(); - const auto channel = _topic->channel().get(); + const auto forum = _topic->forum(); auto showTopicsVisible = rpl::combine( window->adaptive().oneColumnValue(), - window->openedForum().value(), - _1 || (_2 != channel)); + window->shownForum().value(), + _1 || (_2 != forum)); AddMainButton( _wrap, tr::lng_forum_show_topics_list(), std::move(showTopicsVisible), - [=] { window->openForum(channel); }, + [=] { window->showForum(forum); }, tracker); return tracker; } diff --git a/Telegram/SourceFiles/main/main_session.cpp b/Telegram/SourceFiles/main/main_session.cpp index 80be9b409..3b95165bd 100644 --- a/Telegram/SourceFiles/main/main_session.cpp +++ b/Telegram/SourceFiles/main/main_session.cpp @@ -466,6 +466,11 @@ Window::SessionController *Session::tryResolveWindow() const { return nullptr; } } + for (const auto &window : _windows) { + if (window->isPrimary()) { + return window; + } + } return _windows.front(); } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 26c2d88a3..b2c3d843c 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -242,7 +242,10 @@ MainWidget::MainWidget( ? base::make_unique_q(this) : nullptr) , _dialogs(isPrimary() - ? base::make_unique_q(this, _controller) + ? base::make_unique_q( + this, + _controller, + Dialogs::Widget::Layout::Main) : nullptr) , _history(std::in_place, this, _controller) , _playerPlaylist(this, _controller) @@ -612,12 +615,12 @@ bool MainWidget::sendPaths(not_null thread) { Ui::show(Ui::MakeInformBox(*error)); return false; } else { - controller()->showThread( + _controller->showThread( thread, ShowAtTheEndMsgId, Window::SectionShow::Way::ClearStack); } - return (controller()->activeChatCurrent().thread() == thread) + return (_controller->activeChatCurrent().thread() == thread) && (_mainSection ? _mainSection->confirmSendingFiles(cSendPaths()) : _history->confirmSendingFiles(cSendPaths())); @@ -655,11 +658,11 @@ bool MainWidget::onFilesOrForwardDrop( Ui::show(Ui::MakeInformBox(tr::lng_forward_send_files_cant())); return false; } else { - controller()->showThread( + _controller->showThread( thread, ShowAtTheEndMsgId, Window::SectionShow::Way::ClearStack); - if (controller()->activeChatCurrent().thread() != thread) { + if (_controller->activeChatCurrent().thread() != thread) { return false; } (_mainSection @@ -678,7 +681,7 @@ void MainWidget::clearHider(not_null instance) { return; } _hider.release(); - controller()->setSelectingPeer(false); + _controller->setSelectingPeer(false); Assert(_dialogs != nullptr); if (isOneColumn()) { @@ -703,12 +706,12 @@ void MainWidget::clearHider(not_null instance) { } void MainWidget::hiderLayer(base::unique_qptr hider) { - if (!_dialogs || controller()->window().locked()) { + if (!_dialogs || _controller->window().locked()) { return; } _hider = std::move(hider); - controller()->setSelectingPeer(true); + _controller->setSelectingPeer(true); _dialogs->closeForwardBarRequests( ) | rpl::start_with_next([=] { @@ -812,7 +815,7 @@ void MainWidget::clearSelectingPeer() { if (_hider) { _hider->startHide(); _hider.release(); - controller()->setSelectingPeer(false); + _controller->setSelectingPeer(false); } } @@ -821,8 +824,8 @@ void MainWidget::sendBotCommand(Bot::SendCommandRequest request) { ? _mainSection->sendBotCommand(request) : Window::SectionActionResult::Fallback; if (type == Window::SectionActionResult::Fallback) { - ui_showPeerHistory( - request.peer->id, + _controller->showPeerHistory( + request.peer, SectionShow::Way::Forward, ShowAtTheEndMsgId); _history->sendBotCommand(request); @@ -1275,7 +1278,7 @@ void MainWidget::chooseThread( if (selectingPeer()) { _hider->offerThread(thread); } else { - controller()->showThread( + _controller->showThread( thread, showAtMsgId, Window::SectionShow::Way::ClearStack); @@ -1301,8 +1304,8 @@ void MainWidget::showChooseReportMessages( Ui::ReportReason reason, Fn done) { _history->setChooseReportMessagesDetails(reason, std::move(done)); - ui_showPeerHistory( - peer->id, + _controller->showPeerHistory( + peer, SectionShow::Way::Forward, ShowForChooseMessagesMsgId); Ui::ShowMultilineToast({ @@ -1325,7 +1328,7 @@ bool MainWidget::showHistoryInDifferentWindow( MsgId showAtMsgId) { const auto peer = session().data().peer(peerId); if (const auto separate = Core::App().separateWindowForPeer(peer)) { - if (separate == &controller()->window()) { + if (separate == &_controller->window()) { return false; } separate->sessionController()->showPeerHistory( @@ -1351,7 +1354,7 @@ bool MainWidget::showHistoryInDifferentWindow( return true; } -void MainWidget::ui_showPeerHistory( +void MainWidget::showPeerHistory( PeerId peerId, const SectionShow ¶ms, MsgId showAtMsgId) { @@ -1367,7 +1370,7 @@ void MainWidget::ui_showPeerHistory( if (!unavailable.isEmpty()) { Assert(isPrimary()); if (params.activation != anim::activation::background) { - controller()->show(Ui::MakeInformBox(unavailable)); + _controller->show(Ui::MakeInformBox(unavailable)); } return; } @@ -1383,7 +1386,7 @@ void MainWidget::ui_showPeerHistory( if (!(_history->peer() && _history->peer()->id == peerId) && preventsCloseSection( - [=] { ui_showPeerHistory(peerId, params, showAtMsgId); }, + [=] { showPeerHistory(peerId, params, showAtMsgId); }, params)) { return; } @@ -1435,7 +1438,7 @@ void MainWidget::ui_showPeerHistory( const auto wasActivePeer = _controller->activeChatCurrent().peer(); if (params.activation != anim::activation::background) { - controller()->window().hideSettingsAndLayer(); + _controller->window().hideSettingsAndLayer(); } auto animatedShow = [&] { @@ -1484,7 +1487,7 @@ void MainWidget::ui_showPeerHistory( if (noPeer) { _controller->setActiveChatEntry(Dialogs::Key()); - _controller->setChatStyleTheme(controller()->defaultChatTheme()); + _controller->setChatStyleTheme(_controller->defaultChatTheme()); } if (onlyDialogs) { @@ -1547,7 +1550,7 @@ void MainWidget::showMessage( return; } } else if (_history->peer() == item->history()->peer) { - ui_showPeerHistory(peerId, params, itemId); + showPeerHistory(peerId, params, itemId); return; } } @@ -1561,6 +1564,18 @@ void MainWidget::showMessage( } } +void MainWidget::showForum( + not_null forum, + const SectionShow ¶ms) { + Expects(isPrimary() || (singlePeer() && singlePeer()->forum() == forum)); + + _dialogs->showForum(forum, params); + + if (params.activation != anim::activation::background) { + _controller->hideLayer(); + } +} + PeerData *MainWidget::peer() const { return _history->peer(); } @@ -1749,7 +1764,7 @@ void MainWidget::showNewSection( } if (params.activation != anim::activation::background) { - controller()->window().hideSettingsAndLayer(); + _controller->window().hideSettingsAndLayer(); } _controller->setDialogsListFocused(false); @@ -2657,7 +2672,7 @@ void MainWidget::handleHistoryBack() { return; } const auto openedFolder = _controller->openedFolder().current(); - const auto openedForum = _controller->openedForum().current(); + const auto openedForum = _controller->shownForum().current(); const auto rootPeer = !_stack.empty() ? _stack.front()->peer() : _history->peer() diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index c90f5002b..8e1abec74 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -45,6 +45,7 @@ namespace Data { class Thread; class WallPaper; struct ForwardDraft; +class Forum; } // namespace Data namespace Dialogs { @@ -216,13 +217,14 @@ public: void toggleChooseChatTheme(not_null peer); - void ui_showPeerHistory( + void showPeerHistory( PeerId peer, const SectionShow ¶ms, MsgId msgId); void showMessage( not_null item, const SectionShow ¶ms); + void showForum(not_null forum, const SectionShow ¶ms); bool notify_switchInlineBotButtonReceived(const QString &query, UserData *samePeerBot, MsgId samePeerReplyTo); diff --git a/Telegram/SourceFiles/ui/chat/group_call_bar.cpp b/Telegram/SourceFiles/ui/chat/group_call_bar.cpp index 0ea7ad871..b915e4018 100644 --- a/Telegram/SourceFiles/ui/chat/group_call_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/group_call_bar.cpp @@ -248,7 +248,7 @@ void GroupCallBar::setupRightButton(not_null button) { const auto top = (st::historyReplyHeight - st::lineWidth - button->height()) / 2 + st::lineWidth; - const auto narrow = (outerWidth < st::columnMinimalWidthLeft); + const auto narrow = (outerWidth < st::columnMinimalWidthLeft / 2); if (narrow) { button->moveToLeft( (outerWidth - buttonWidth) / 2, @@ -265,7 +265,7 @@ void GroupCallBar::setupRightButton(not_null button) { void GroupCallBar::paint(Painter &p) { p.fillRect(_inner->rect(), st::historyComposeAreaBg); - const auto narrow = (_inner->width() < st::columnMinimalWidthLeft); + const auto narrow = (_inner->width() < st::columnMinimalWidthLeft / 2); if (!narrow) { paintTitleAndStatus(p); paintUserpics(p); diff --git a/Telegram/SourceFiles/ui/chat/requests_bar.cpp b/Telegram/SourceFiles/ui/chat/requests_bar.cpp index 69190a745..9636e02ce 100644 --- a/Telegram/SourceFiles/ui/chat/requests_bar.cpp +++ b/Telegram/SourceFiles/ui/chat/requests_bar.cpp @@ -151,7 +151,7 @@ void RequestsBar::paint(Painter &p) { p.setPen(st::defaultMessageBar.titleFg); p.setFont(font); - if (width >= st::columnMinimalWidthLeft) { + if (width >= st::columnMinimalWidthLeft / 2) { const auto textLeft = userpicsLeft + _userpicsWidth + userpicsLeft; const auto available = width - textLeft - userpicsLeft; if (_textFull.isEmpty() || available < _textFull.maxWidth()) { diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index ee27fd125..78c2351b3 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -372,7 +372,7 @@ void SessionNavigation::showPeerByLinkResolved( } else if (peer->isForum()) { const auto itemId = info.messageId; if (!itemId) { - parentController()->openForum(peer->asChannel(), params); + parentController()->showForum(peer->forum(), params); } else if (const auto item = peer->owner().message(peer, itemId)) { showMessageByLinkResolved(item, info); } else { @@ -974,13 +974,22 @@ void SessionController::closeFolder() { _openedFolder = nullptr; } -void SessionController::openForum( - not_null forum, +void SessionController::showForum( + not_null forum, const SectionShow ¶ms) { - Expects(forum->isForum()); - - _openedForumLifetime.destroy(); - if (_openedForum.current() != forum) { + if (!isPrimary()) { + const auto primary = Core::App().primaryWindow(); + if (&primary->account() != &session().account()) { + primary->showAccount(&session().account()); + } + if (&primary->account() == &session().account()) { + primary->sessionController()->showForum(forum, params); + } + primary->activate(); + return; + } + _shownForumLifetime.destroy(); + if (_shownForum.current() != forum) { resetFakeUnreadWhileOpened(); } if (forum @@ -988,24 +997,23 @@ void SessionController::openForum( && adaptive().isOneColumn()) { clearSectionStack(params); } - _openedForum = forum.get(); - if (_openedForum.current() == forum) { - forum->forum()->destroyed( - ) | rpl::start_with_next([=] { - closeForum(); - showPeerHistory( - forum, - { anim::type::normal, anim::activation::background }); - }, _openedForumLifetime); - } - if (params.activation != anim::activation::background) { - hideLayer(); + _shownForum = forum.get(); + if (_shownForum.current() != forum) { + return; } + forum->destroyed( + ) | rpl::start_with_next([=, history = forum->history()] { + closeForum(); + showPeerHistory( + history, + { anim::type::normal, anim::activation::background }); + }, _shownForumLifetime); + content()->showForum(forum, params); } void SessionController::closeForum() { - _openedForumLifetime.destroy(); - _openedForum = nullptr; + _shownForumLifetime.destroy(); + _shownForum = nullptr; } void SessionController::setupPremiumToast() { @@ -1037,8 +1045,8 @@ const rpl::variable &SessionController::openedFolder() const { return _openedFolder; } -const rpl::variable &SessionController::openedForum() const { - return _openedForum; +const rpl::variable &SessionController::shownForum() const { + return _shownForum; } void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) { @@ -1062,9 +1070,9 @@ void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) { ) | rpl::start_with_next([=] { clearSectionStack( { anim::type::normal, anim::activation::background }); - openForum(channel, + showForum(channel->forum(), { anim::type::normal, anim::activation::background }); - }, _openedForumLifetime); + }, _shownForumLifetime); } } if (session().supportMode()) { @@ -1674,7 +1682,7 @@ void SessionController::showPeerHistory( PeerId peerId, const SectionShow ¶ms, MsgId msgId) { - content()->ui_showPeerHistory(peerId, params, msgId); + content()->showPeerHistory(peerId, params, msgId); } void SessionController::showMessage( diff --git a/Telegram/SourceFiles/window/window_session_controller.h b/Telegram/SourceFiles/window/window_session_controller.h index 5c6bc6dda..05a54dfcc 100644 --- a/Telegram/SourceFiles/window/window_session_controller.h +++ b/Telegram/SourceFiles/window/window_session_controller.h @@ -69,6 +69,7 @@ namespace Data { struct CloudTheme; enum class CloudThemeType; class Thread; +class Forum; class ForumTopic; } // namespace Data @@ -151,19 +152,25 @@ struct SectionShow { , activation(activation) { } - SectionShow withWay(Way newWay) const { + [[nodiscard]] SectionShow withWay(Way newWay) const { return SectionShow(newWay, animated, activation); } - SectionShow withThirdColumn() const { + [[nodiscard]] SectionShow withThirdColumn() const { auto copy = *this; copy.thirdColumn = true; return copy; } + [[nodiscard]] SectionShow withChildColumn() const { + auto copy = *this; + copy.childColumn = true; + return copy; + } Way way = Way::Forward; anim::type animated = anim::type::normal; anim::activation activation = anim::activation::normal; bool thirdColumn = false; + bool childColumn = false; Origin origin; }; @@ -358,11 +365,11 @@ public: void closeFolder(); const rpl::variable &openedFolder() const; - void openForum( - not_null forum, + void showForum( + not_null forum, const SectionShow ¶ms = SectionShow::Way::ClearStack); void closeForum(); - const rpl::variable &openedForum() const; + const rpl::variable &shownForum() const; void setActiveChatEntry(Dialogs::RowDescriptor row); void setActiveChatEntry(Dialogs::Key key); @@ -634,8 +641,8 @@ private: PeerData *_showEditPeer = nullptr; rpl::variable _openedFolder; - rpl::variable _openedForum; - rpl::lifetime _openedForumLifetime; + rpl::variable _shownForum; + rpl::lifetime _shownForumLifetime; rpl::event_stream<> _filtersMenuChanged;