From 5a7d8bcffbf60c10bda079c426d78b3ec590b7eb Mon Sep 17 00:00:00 2001 From: John Preston Date: Sat, 9 Dec 2017 19:13:06 +0400 Subject: [PATCH] Add audio playlist using Info::Media::ListWidget. --- .../history/history_media_types.cpp | 6 +- .../info_common_groups_inner_widget.cpp | 2 +- Telegram/SourceFiles/info/info_controller.cpp | 42 ++- Telegram/SourceFiles/info/info_controller.h | 69 +++-- .../SourceFiles/info/info_wrap_widget.cpp | 12 +- .../info/media/info_media_list_widget.cpp | 48 +++- .../info/media/info_media_list_widget.h | 20 +- .../info/profile/info_profile_actions.cpp | 4 +- .../info/profile/info_profile_cover.cpp | 2 +- .../info/profile/info_profile_members.cpp | 2 +- Telegram/SourceFiles/mainwidget.cpp | 7 +- .../media/player/media_player.style | 2 +- .../media/player/media_player_instance.cpp | 2 +- .../media/player/media_player_panel.cpp | 250 +++++++++++++----- .../media/player/media_player_panel.h | 51 +++- .../SourceFiles/window/window_peer_menu.cpp | 3 +- .../SourceFiles/window/window_peer_menu.h | 6 +- 17 files changed, 390 insertions(+), 138 deletions(-) diff --git a/Telegram/SourceFiles/history/history_media_types.cpp b/Telegram/SourceFiles/history/history_media_types.cpp index e69043e27..8a62fd51a 100644 --- a/Telegram/SourceFiles/history/history_media_types.cpp +++ b/Telegram/SourceFiles/history/history_media_types.cpp @@ -1148,12 +1148,12 @@ void HistoryDocument::initDimensions() { if (thumbed) { _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); - if (!captioned && (_parent->Has() || _parent->Has())) { - _minh += st::msgDateFont->height - st::msgDateDelta.y(); - } } else { _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); } + if (!captioned && (_parent->Has() || _parent->Has())) { + _minh += st::msgDateFont->height - st::msgDateDelta.y(); + } if (!isBubbleTop()) { _minh -= st::msgFileTopMinus; } diff --git a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp index 5ef0fd85b..4c28d591f 100644 --- a/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp +++ b/Telegram/SourceFiles/info/common_groups/info_common_groups_inner_widget.cpp @@ -165,7 +165,7 @@ void ListController::restoreState( } void ListController::rowClicked(not_null row) { - _controller->window()->showPeerHistory( + _controller->parentController()->showPeerHistory( row->peer(), Window::SectionShow::Way::Forward); } diff --git a/Telegram/SourceFiles/info/info_controller.cpp b/Telegram/SourceFiles/info/info_controller.cpp index 823b0f4ef..59974c923 100644 --- a/Telegram/SourceFiles/info/info_controller.cpp +++ b/Telegram/SourceFiles/info/info_controller.cpp @@ -44,16 +44,46 @@ not_null CorrectPeer(PeerId peerId) { } // namespace +rpl::producer AbstractController::mediaSource( + SparseIdsMergedSlice::UniversalMsgId aroundId, + int limitBefore, + int limitAfter) const { + return SharedMediaMergedViewer( + SharedMediaMergedKey( + SparseIdsMergedSlice::Key( + peerId(), + migratedPeerId(), + aroundId), + section().mediaType()), + limitBefore, + limitAfter); +} + +rpl::producer AbstractController::mediaSourceQueryValue() const { + return rpl::single(QString()); +} + +void AbstractController::showSection( + Window::SectionMemento &&memento, + const Window::SectionShow ¶ms) { + return parentController()->showSection(std::move(memento), params); +} + +void AbstractController::showBackFromStack( + const Window::SectionShow ¶ms) { + return parentController()->showBackFromStack(params); +} + Controller::Controller( not_null widget, not_null window, not_null memento) -: _widget(widget) +: AbstractController(window) +, _widget(widget) , _peer(App::peer(memento->peerId())) , _migrated(memento->migratedPeerId() ? App::peer(memento->migratedPeerId()) : nullptr) -, _window(window) , _section(memento->section()) { updateSearchControllers(memento); setupMigrationViewer(); @@ -66,11 +96,11 @@ void Controller::setupMigrationViewer() { Notify::PeerUpdateValue(_peer, Notify::PeerUpdate::Flag::MigrationChanged) | rpl::start_with_next([this] { if (_peer->migrateTo() || (_peer->migrateFrom() != _migrated)) { - auto windowController = window(); + auto window = parentController(); auto peerId = _peer->id; auto section = _section; InvokeQueued(_widget, [=] { - windowController->showSection( + window->showSection( Memento(peerId, section), Window::SectionShow( Window::SectionShow::Way::Backward, @@ -162,13 +192,13 @@ void Controller::showSection( Window::SectionMemento &&memento, const Window::SectionShow ¶ms) { if (!_widget->showInternal(&memento, params)) { - _window->showSection(std::move(memento), params); + AbstractController::showSection(std::move(memento), params); } } void Controller::showBackFromStack(const Window::SectionShow ¶ms) { if (!_widget->showBackFromStackInternal(params)) { - _window->showBackFromStack(params); + AbstractController::showBackFromStack(params); } } diff --git a/Telegram/SourceFiles/info/info_controller.h b/Telegram/SourceFiles/info/info_controller.h index 1973eca8a..314e20128 100644 --- a/Telegram/SourceFiles/info/info_controller.h +++ b/Telegram/SourceFiles/info/info_controller.h @@ -67,26 +67,62 @@ private: }; -class Controller : public Window::Navigation { +class AbstractController : public Window::Navigation { +public: + AbstractController(not_null parent) + : _parent(parent) { + } + + virtual not_null peer() const = 0; + virtual PeerData *migrated() const = 0; + virtual Section section() const = 0; + + PeerId peerId() const { + return peer()->id; + } + PeerId migratedPeerId() const { + if (auto peer = migrated()) { + return peer->id; + } + return PeerId(0); + } + + virtual void setSearchEnabledByContent(bool enabled) { + } + virtual rpl::producer mediaSource( + SparseIdsMergedSlice::UniversalMsgId aroundId, + int limitBefore, + int limitAfter) const; + virtual rpl::producer mediaSourceQueryValue() const; + + void showSection( + Window::SectionMemento &&memento, + const Window::SectionShow ¶ms = Window::SectionShow()) override; + void showBackFromStack( + const Window::SectionShow ¶ms = Window::SectionShow()) override; + not_null parentController() override { + return _parent; + } + +private: + not_null _parent; + +}; + +class Controller : public AbstractController { public: Controller( not_null widget, not_null window, not_null memento); - not_null peer() const { + not_null peer() const override { return _peer; } - PeerData *migrated() const { + PeerData *migrated() const override { return _migrated; } - PeerId peerId() const { - return _peer->id; - } - PeerId migratedPeerId() const { - return _migrated ? _migrated->id : PeerId(0); - } - const Section §ion() const { + Section section() const override { return _section; } @@ -97,21 +133,18 @@ public: rpl::producer wrapValue() const; void setSection(not_null memento); - not_null window() const { - return _window; - } Ui::SearchFieldController *searchFieldController() const { return _searchFieldController.get(); } - void setSearchEnabledByContent(bool enabled) { + void setSearchEnabledByContent(bool enabled) override { _seachEnabledByContent = enabled; } rpl::producer searchEnabledByContent() const; rpl::producer mediaSource( SparseIdsMergedSlice::UniversalMsgId aroundId, int limitBefore, - int limitAfter) const; - rpl::producer mediaSourceQueryValue() const; + int limitAfter) const override; + rpl::producer mediaSourceQueryValue() const override; bool takeSearchStartsFocused() { return base::take(_searchStartsFocused); } @@ -123,9 +156,6 @@ public: const Window::SectionShow ¶ms = Window::SectionShow()) override; void showBackFromStack( const Window::SectionShow ¶ms = Window::SectionShow()) override; - not_null parentController() override { - return _window; - } rpl::lifetime &lifetime() { return _lifetime; @@ -143,7 +173,6 @@ private: not_null _widget; not_null _peer; PeerData *_migrated = nullptr; - not_null _window; rpl::variable _wrap; Section _section; diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index 887c12b80..ffbfc172b 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -116,7 +116,7 @@ void WrapWidget::startInjectingActivePeerProfiles() { using namespace rpl::mappers; rpl::combine( _wrap.value(), - _controller->window()->activePeer.value()) + _controller->parentController()->activePeer.value()) | rpl::filter((_1 == Wrap::Side) && (_2 != nullptr)) | rpl::map(_2) | rpl::start_with_next([this](not_null peer) { @@ -241,7 +241,7 @@ void WrapWidget::forceContentRepaint() { // _anotherTabMemento = createTabMemento(tab); // } // auto newController = createController( -// _controller->window(), +// _controller->parentController(), // _anotherTabMemento.get()); // auto newContent = createContent( // _anotherTabMemento.get(), @@ -331,7 +331,7 @@ void WrapWidget::createTopBar() { _topBar, st::infoTopBarClose)); close->addClickHandler([this] { - _controller->window()->closeThirdSection(); + _controller->parentController()->closeThirdSection(); }); } if (wrapValue == Wrap::Layer) { @@ -340,7 +340,7 @@ void WrapWidget::createTopBar() { _topBar, st::infoLayerTopBarClose)); close->addClickHandler([this] { - _controller->window()->hideSpecialLayer(); + _controller->parentController()->hideSpecialLayer(); }); } else if (requireTopBarSearch()) { auto search = _controller->searchFieldController(); @@ -465,7 +465,7 @@ void WrapWidget::showProfileMenu() { _topBarMenuToggle->installEventFilter(_topBarMenu.get()); Window::FillPeerMenu( - _controller->window(), + _controller->parentController(), _controller->peer(), [this](const QString &text, base::lambda callback) { return _topBarMenu->addAction(text, std::move(callback)); @@ -788,7 +788,7 @@ void WrapWidget::showNewContent( && (params.animated != anim::type::instant); auto animationParams = SectionSlideParams(); auto newController = createController( - _controller->window(), + _controller->parentController(), memento); auto newContent = object_ptr(nullptr); if (needAnimation) { diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp index 986e963c3..0e5a88e20 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.cpp +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.cpp @@ -35,6 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "window/main_window.h" #include "styles/style_overview.h" #include "styles/style_info.h" +#include "media/player/media_player_instance.h" #include "boxes/peer_list_controllers.h" #include "boxes/confirm_box.h" #include "core/file_utilities.h" @@ -546,7 +547,7 @@ void ListWidget::Section::refreshHeight() { ListWidget::ListWidget( QWidget *parent, - not_null controller) + not_null controller) : RpWidget(parent) , _controller(controller) , _peer(_controller->peer()) @@ -594,6 +595,18 @@ rpl::producer ListWidget::selectedListValue() const { collectSelectedItems()); } +QRect ListWidget::getCurrentSongGeometry() { + const auto type = AudioMsgId::Type::Song; + const auto current = ::Media::Player::instance()->current(type); + const auto fullMsgId = current.contextId(); + if (fullMsgId && isPossiblyMyId(fullMsgId)) { + if (const auto item = findItemById(GetUniversalId(fullMsgId))) { + return item->geometry; + } + } + return QRect(0, 0, width(), 0); +} + void ListWidget::restart() { mouseActionCancel(); @@ -1347,6 +1360,7 @@ void ListWidget::showContextMenu( _contextMenu = nullptr; mouseActionUpdate(QCursor::pos()); repaintItem(universalId); + _checkForHide.fire({}); })); _contextMenu->popup(e->globalPos()); e->accept(); @@ -1373,12 +1387,14 @@ void ListWidget::forwardItem(UniversalMsgId universalId) { } void ListWidget::forwardItems(MessageIdsList &&items) { - const auto weak = make_weak(this); - Window::ShowForwardMessagesBox(std::move(items), [weak] { + auto callback = [weak = make_weak(this)] { if (const auto strong = weak.data()) { strong->clearSelected(); } - }); + }; + setActionBoxWeak(Window::ShowForwardMessagesBox( + std::move(items), + std::move(callback))); } void ListWidget::deleteSelected() { @@ -1393,7 +1409,19 @@ void ListWidget::deleteItem(UniversalMsgId universalId) { void ListWidget::deleteItems(MessageIdsList &&items) { if (!items.empty()) { - Ui::show(Box(std::move(items))); + const auto box = Ui::show(Box(std::move(items))); + setActionBoxWeak(box.data()); + } +} + +void ListWidget::setActionBoxWeak(QPointer box) { + if ((_actionBoxWeak = box)) { + _actionBoxWeakLifetime = _actionBoxWeak->alive( + ) | rpl::start_with_done([weak = make_weak(this)]{ + if (weak) { + weak->_checkForHide.fire({}); + } + }); } } @@ -1768,8 +1796,8 @@ void ListWidget::mouseActionStart(const QPoint &screenPos, Qt::MouseButton butto auto pressLayout = _overLayout; _mouseAction = MouseAction::None; - _pressWasInactive = _controller->window()->window()->wasInactivePress(); - if (_pressWasInactive) _controller->window()->window()->setInactivePress(false); + _pressWasInactive = _controller->parentController()->window()->wasInactivePress(); + if (_pressWasInactive) _controller->parentController()->window()->setInactivePress(false); if (ClickHandler::getPressed() && !hasSelected()) { _mouseAction = MouseAction::PrepareDrag; @@ -1893,7 +1921,7 @@ void ListWidget::performDrag() { // mimeData->setData(qsl("application/x-td-forward-selected"), "1"); // } // } - // _controller->window()->launchDrag(std::move(mimeData)); + // _controller->parentController()->window()->launchDrag(std::move(mimeData)); // return; //} else { // auto forwardMimeType = QString(); @@ -1924,7 +1952,7 @@ void ListWidget::performDrag() { // } // // This call enters event loop and can destroy any QObject. - // _controller->window()->launchDrag(std::move(mimeData)); + // _controller->parentController()->window()->launchDrag(std::move(mimeData)); // return; // } //} @@ -1974,7 +2002,7 @@ void ListWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton butt if (selection.text != FullSelection && selection.text.from == selection.text.to) { clearSelected(); - //_controller->window()->setInnerFocus(); // #TODO focus + //_controller->parentController()->window()->setInnerFocus(); // #TODO focus } } } diff --git a/Telegram/SourceFiles/info/media/info_media_list_widget.h b/Telegram/SourceFiles/info/media/info_media_list_widget.h index eff50591f..4f0c87418 100644 --- a/Telegram/SourceFiles/info/media/info_media_list_widget.h +++ b/Telegram/SourceFiles/info/media/info_media_list_widget.h @@ -40,7 +40,7 @@ class Controller; namespace Info { -class Controller; +class AbstractController; namespace Media { @@ -51,7 +51,7 @@ class ListWidget : public Ui::RpWidget { public: ListWidget( QWidget *parent, - not_null controller); + not_null controller); void restart(); @@ -61,6 +61,14 @@ public: clearSelected(); } + QRect getCurrentSongGeometry(); + rpl::producer<> checkForHide() const { + return _checkForHide.events(); + } + bool preventAutoHide() const { + return (_contextMenu != nullptr) || (_actionBoxWeak != nullptr); + } + void saveState(not_null memento); void restoreState(not_null memento); @@ -259,7 +267,9 @@ private: void validateTrippleClickStartTime(); void checkMoveToOtherViewer(); - const not_null _controller; + void setActionBoxWeak(QPointer box); + + const not_null _controller; const not_null _peer; PeerData * const _migrated = nullptr; Type _type = Type::Photo; @@ -294,7 +304,11 @@ private: style::cursor _cursor = style::cur_default; DragSelectAction _dragSelectAction = DragSelectAction::None; bool _wasSelectedText = false; // was some text selected in current drag action + Ui::PopupMenu *_contextMenu = nullptr; + rpl::event_stream<> _checkForHide; + QPointer _actionBoxWeak; + rpl::lifetime _actionBoxWeakLifetime; QPoint _trippleClickPoint; TimeMs _trippleClickStartTime = 0; diff --git a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp index b398dd415..f77e94c76 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_actions.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_actions.cpp @@ -325,7 +325,7 @@ Ui::MultiSlideTracker DetailsFiller::fillUserButtons( using namespace rpl::mappers; Ui::MultiSlideTracker tracker; - auto window = _controller->window(); + auto window = _controller->parentController(); auto addSendMessageButton = [&] { auto sendMessageVisible = rpl::combine( @@ -377,7 +377,7 @@ Ui::MultiSlideTracker DetailsFiller::fillChannelButtons( using namespace rpl::mappers; Ui::MultiSlideTracker tracker; - auto window = _controller->window(); + auto window = _controller->parentController(); auto viewChannelVisible = rpl::combine( _controller->wrapValue(), window->historyPeer.value(), diff --git a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp index 2a277963e..bf3a6b919 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_cover.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_cover.cpp @@ -234,7 +234,7 @@ Cover::Cover( , _peer(peer) , _userpic( this, - controller->window(), + controller->parentController(), _peer, Ui::UserpicButton::Role::OpenPhoto, st::infoProfilePhoto) diff --git a/Telegram/SourceFiles/info/profile/info_profile_members.cpp b/Telegram/SourceFiles/info/profile/info_profile_members.cpp index 3507757f7..c500baf9a 100644 --- a/Telegram/SourceFiles/info/profile/info_profile_members.cpp +++ b/Telegram/SourceFiles/info/profile/info_profile_members.cpp @@ -74,7 +74,7 @@ Members::Members( | rpl::start_with_next([this](int count) { const auto enabled = (count >= kEnableSearchMembersAfterCount); _controller->setSearchEnabledByContent(enabled); - }); + }, lifetime()); } int Members::desiredHeight() const { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index c5589989e..5ca98a9a3 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -198,8 +198,11 @@ MainWidget::MainWidget( , _sideShadow(this) , _dialogs(this, _controller) , _history(this, _controller) -, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist) -, _playerPanel(this, Media::Player::Panel::Layout::Full) { +, _playerPlaylist( + this, + _controller, + Media::Player::Panel::Layout::OnlyPlaylist) +, _playerPanel(this, _controller, Media::Player::Panel::Layout::Full) { Messenger::Instance().mtp()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived)); Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail)); diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style index 5c8ddab0f..74281aa64 100644 --- a/Telegram/SourceFiles/media/player/media_player.style +++ b/Telegram/SourceFiles/media/player/media_player.style @@ -226,7 +226,7 @@ mediaPlayerPanelVolumeToggleTop: 57px; mediaPlayerScroll: ScrollArea(defaultSolidScroll) { deltat: 10px; - deltab: 0px; + deltab: 10px; } mediaPlayerListHeightMax: 280px; mediaPlayerListMarginBottom: 10px; diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index 5e2e2c1d5..c4ab0aab1 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -199,7 +199,7 @@ auto Instance::playlistKey(not_null data) const -> base::optional { const auto contextId = data->current.contextId(); const auto history = data->history; - if (!contextId || !history) { + if (!contextId || !history || !IsServerMsgId(contextId.msg)) { return {}; } diff --git a/Telegram/SourceFiles/media/player/media_player_panel.cpp b/Telegram/SourceFiles/media/player/media_player_panel.cpp index 989737183..08eab44b5 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.cpp +++ b/Telegram/SourceFiles/media/player/media_player_panel.cpp @@ -22,25 +22,36 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "media/player/media_player_cover.h" #include "media/player/media_player_instance.h" -#include "styles/style_overview.h" -#include "styles/style_widgets.h" -#include "styles/style_media_player.h" +#include "info/media/info_media_list_widget.h" #include "ui/widgets/shadow.h" #include "ui/widgets/scroll_area.h" #include "mainwindow.h" +#include "styles/style_overview.h" +#include "styles/style_widgets.h" +#include "styles/style_media_player.h" +#include "styles/style_info.h" namespace Media { namespace Player { +namespace { -Panel::Panel(QWidget *parent, Layout layout) : TWidget(parent) +using ListWidget = Info::Media::ListWidget; + +constexpr auto kPlaylistIdsLimit = 32; +constexpr auto kDelayedHideTimeout = TimeMs(3000); + +} // namespace + +Panel::Panel( + QWidget *parent, + not_null window, + Layout layout) +: RpWidget(parent) +, AbstractController(window) , _layout(layout) +, _showTimer([this] { startShow(); }) +, _hideTimer([this] { startHideChecked(); }) , _scroll(this, st::mediaPlayerScroll) { - _hideTimer.setSingleShot(true); - connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideStart())); - - _showTimer.setSingleShot(true); - connect(&_showTimer, SIGNAL(timeout()), this, SLOT(onShowStart())); - hide(); updateSize(); } @@ -53,7 +64,7 @@ bool Panel::overlaps(const QRect &globalRect) { return rect().marginsRemoved(QMargins(marginLeft, contentTop(), marginRight, contentBottom())).contains(QRect(mapFromGlobal(globalRect.topLeft()), globalRect.size())); } -void Panel::onWindowActiveChanged() { +void Panel::windowActiveChanged() { if (!App::wnd()->windowHandle()->isActive() && !isHidden()) { leaveEvent(nullptr); } @@ -63,16 +74,36 @@ void Panel::resizeEvent(QResizeEvent *e) { updateControlsGeometry(); } -void Panel::onListHeightUpdated() { - if (auto widget = _scroll->widget()) { - if (widget->height() > 0 || _cover) { - updateSize(); - } else { - hideIgnoringEnterEvents(); - } +void Panel::listHeightUpdated(int newHeight) { + if (newHeight > emptyInnerHeight() || _cover) { + updateSize(); + } else { + _hideTimer.callOnce(0); } } +bool Panel::contentTooSmall() const { + const auto innerHeight = _scroll->widget() + ? _scroll->widget()->height() + : emptyInnerHeight(); + return (innerHeight <= emptyInnerHeight() && !_cover); +} + +int Panel::emptyInnerHeight() const { + return st::infoMediaMargin.top() + + st::overviewFileLayout.songPadding.top() + + st::overviewFileLayout.songThumbSize + + st::overviewFileLayout.songPadding.bottom() + + st::infoMediaMargin.bottom(); +} + +bool Panel::preventAutoHide() const { + if (const auto list = static_cast(_scroll->widget())) { + return list->preventAutoHide(); + } + return false; +} + void Panel::updateControlsGeometry() { auto scrollTop = contentTop(); auto width = contentWidth(); @@ -91,7 +122,6 @@ void Panel::updateControlsGeometry() { } if (auto widget = static_cast(_scroll->widget())) { widget->resizeToWidth(width); - onScroll(); } } @@ -103,19 +133,9 @@ int Panel::bestPositionFor(int left) const { } void Panel::scrollPlaylistToCurrentTrack() { - // #TODO playlist - //if (auto list = static_cast(_scroll->widget())) { - // auto rect = list->getCurrentTrackGeometry(); - // auto top = _scroll->scrollTop(), bottom = top + _scroll->height(); - // _scroll->scrollToY(rect.y()); - //} -} - -void Panel::onScroll() { - if (auto widget = static_cast(_scroll->widget())) { - int visibleTop = _scroll->scrollTop(); - int visibleBottom = visibleTop + _scroll->height(); - widget->setVisibleTopBottom(visibleTop, visibleBottom); + if (const auto list = static_cast(_scroll->widget())) { + const auto rect = list->getCurrentSongGeometry(); + _scroll->scrollToY(rect.y() - st::infoMediaMargin.top()); } } @@ -170,42 +190,45 @@ void Panel::paintEvent(QPaintEvent *e) { } void Panel::enterEventHook(QEvent *e) { - if (_ignoringEnterEvents) return; + if (_ignoringEnterEvents || contentTooSmall()) return; - _hideTimer.stop(); + _hideTimer.cancel(); if (_a_appearance.animating(getms())) { - onShowStart(); + startShow(); } else { - _showTimer.start(0); + _showTimer.callOnce(0); } return TWidget::enterEventHook(e); } void Panel::leaveEventHook(QEvent *e) { - _showTimer.stop(); + if (preventAutoHide()) { + return; + } + _showTimer.cancel(); if (_a_appearance.animating(getms())) { - onHideStart(); + startHide(); } else { - _hideTimer.start(300); + _hideTimer.callOnce(300); } return TWidget::leaveEventHook(e); } void Panel::showFromOther() { - _hideTimer.stop(); + _hideTimer.cancel(); if (_a_appearance.animating(getms())) { - onShowStart(); + startShow(); } else { - _showTimer.start(300); + _showTimer.callOnce(300); } } void Panel::hideFromOther() { - _showTimer.stop(); + _showTimer.cancel(); if (_a_appearance.animating(getms())) { - onHideStart(); + startHide(); } else { - _hideTimer.start(0); + _hideTimer.callOnce(0); } } @@ -219,32 +242,108 @@ void Panel::ensureCreated() { _scrollShadow.create(this, st::mediaPlayerScrollShadow, RectPart::Bottom); } - // #TODO playlist - //auto list = object_ptr(this); - //connect(list, SIGNAL(heightUpdated()), this, SLOT(onListHeightUpdated())); - //_scroll->setOwnedWidget(std::move(list)); + _refreshListLifetime = instance()->playlistChanges( + AudioMsgId::Type::Song + ) | rpl::start_with_next([this] { + refreshList(); + }); + refreshList(); if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { - if (auto window = App::wnd()) { - connect(window->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged())); + if (const auto window = App::wnd()) { + connect( + window->windowHandle(), + &QWindow::activeChanged, + this, + &Panel::windowActiveChanged); } } - updateSize(); - updateControlsGeometry(); _ignoringEnterEvents = false; } +void Panel::refreshList() { + const auto current = instance()->current(AudioMsgId::Type::Song); + const auto contextId = current.contextId(); + const auto peer = [&]() -> PeerData* { + const auto item = contextId ? App::histItemById(contextId) : nullptr; + if (item) { + const auto result = item->history()->peer; + if (const auto migrated = result->migrateTo()) { + return migrated; + } + return result; + } + return nullptr; + }(); + const auto migrated = peer ? peer->migrateFrom() : nullptr; + if (_listPeer != peer || _listMigratedPeer != migrated) { + _scroll->takeWidget().destroy(); + _listPeer = _listMigratedPeer = nullptr; + } + if (peer && !_listPeer) { + _listPeer = peer; + _listMigratedPeer = migrated; + auto list = object_ptr(this, infoController()); + + const auto weak = _scroll->setOwnedWidget(std::move(list)); + + updateSize(); + updateControlsGeometry(); + + weak->checkForHide( + ) | rpl::start_with_next([this] { + if (!rect().contains(mapFromGlobal(QCursor::pos()))) { + _hideTimer.callOnce(kDelayedHideTimeout); + } + }, weak->lifetime()); + + weak->heightValue( + ) | rpl::start_with_next([this](int newHeight) { + listHeightUpdated(newHeight); + }, weak->lifetime()); + + weak->scrollToRequests( + ) | rpl::start_with_next([this](int newScrollTop) { + _scroll->scrollToY(newScrollTop); + }, weak->lifetime()); + + using namespace rpl::mappers; + rpl::combine( + _scroll->scrollTopValue(), + _scroll->heightValue(), + tuple(_1, _1 + _2) + ) | rpl::start_with_next([=](int top, int bottom) { + weak->setVisibleTopBottom(top, bottom); + }, weak->lifetime()); + + auto memento = Info::Media::Memento( + peerId(), + migratedPeerId(), + section().mediaType()); + memento.setAroundId(contextId); + memento.setIdsLimit(kPlaylistIdsLimit); + memento.setScrollTopItem(contextId); + memento.setScrollTopShift(-st::infoMediaMargin.top()); + weak->restoreState(&memento); + } +} + void Panel::performDestroy() { if (!_scroll->widget()) return; _cover.destroy(); - // #TODO playlist - //_scroll->takeWidget().destroyDelayed(); + _scroll->takeWidget().destroy(); + _listPeer = _listMigratedPeer = nullptr; + _refreshListLifetime.destroy(); if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { - if (auto window = App::wnd()) { - disconnect(window->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged())); + if (const auto window = App::wnd()) { + disconnect( + window->windowHandle(), + &QWindow::activeChanged, + this, + &Panel::windowActiveChanged); } } } @@ -263,12 +362,22 @@ void Panel::setCloseCallback(ButtonCallback &&callback) { } } -void Panel::onShowStart() { +not_null Panel::peer() const { + return _listPeer; +} + +PeerData *Panel::migrated() const { + return _listMigratedPeer; +} + +Info::Section Panel::section() const { + return Info::Section(Info::Section::MediaType::MusicFile); +} + +void Panel::startShow() { ensureCreated(); - if (auto widget = _scroll->widget()) { - if (widget->height() <= 0 && !_cover) { - return; - } + if (contentTooSmall()) { + return; } if (isHidden()) { @@ -286,11 +395,22 @@ void Panel::hideIgnoringEnterEvents() { if (isHidden()) { hideFinished(); } else { - onHideStart(); + startHide(); } } -void Panel::onHideStart() { +void Panel::startHideChecked() { + if (!contentTooSmall() && preventAutoHide()) { + return; + } + if (isHidden()) { + hideFinished(); + } else { + startHide(); + } +} + +void Panel::startHide() { if (_hiding || isHidden()) return; _hiding = true; @@ -340,7 +460,7 @@ int Panel::contentBottom() const { } int Panel::scrollMarginBottom() const { - return st::mediaPlayerPanelMarginBottom; + return 0;// st::mediaPlayerPanelMarginBottom; } } // namespace Player diff --git a/Telegram/SourceFiles/media/player/media_player_panel.h b/Telegram/SourceFiles/media/player/media_player_panel.h index a506e6105..04e5064eb 100644 --- a/Telegram/SourceFiles/media/player/media_player_panel.h +++ b/Telegram/SourceFiles/media/player/media_player_panel.h @@ -20,6 +20,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +#include "base/timer.h" +#include "ui/rp_widget.h" +#include "info/info_controller.h" + +namespace Window { +class Controller; +} // namespace Window + namespace Ui { class ScrollArea; class Shadow; @@ -30,15 +38,16 @@ namespace Player { class CoverWidget; -class Panel : public TWidget { - Q_OBJECT - +class Panel : public Ui::RpWidget, private Info::AbstractController { public: enum class Layout { Full, OnlyPlaylist, }; - Panel(QWidget *parent, Layout layout); + Panel( + QWidget *parent, + not_null controller, + Layout layout); bool overlaps(const QRect &globalRect); @@ -59,20 +68,26 @@ protected: void enterEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override; -private slots: - void onShowStart(); - void onHideStart(); - - void onScroll(); - void onListHeightUpdated(); - void onWindowActiveChanged(); - private: + // Info::AbstractController implementation. + not_null peer() const override; + PeerData *migrated() const override; + Info::Section section() const override; + + void startShow(); + void startHide(); + void startHideChecked(); + bool preventAutoHide() const; + void listHeightUpdated(int newHeight); + int emptyInnerHeight() const; + bool contentTooSmall() const; + void windowActiveChanged(); + void ensureCreated(); void performDestroy(); void updateControlsGeometry(); - + void refreshList(); void updateSize(); void appearanceCallback(); void hideFinished(); @@ -90,6 +105,9 @@ private: void startAnimation(); void scrollPlaylistToCurrentTrack(); + not_null infoController() { + return static_cast(this); + } Layout _layout; bool _hiding = false; @@ -99,13 +117,18 @@ private: bool _ignoringEnterEvents = false; - QTimer _hideTimer, _showTimer; + base::Timer _showTimer; + base::Timer _hideTimer; ButtonCallback _pinCallback, _closeCallback; object_ptr _cover = { nullptr }; object_ptr _scroll; object_ptr _scrollShadow = { nullptr }; + rpl::lifetime _refreshListLifetime; + PeerData *_listPeer = nullptr; + PeerData *_listMigratedPeer = nullptr; + }; } // namespace Clip diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 3a2d5738a..1479b1b0a 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -457,7 +457,7 @@ void PeerMenuShareContactBox(not_null user) { })); } -void ShowForwardMessagesBox( +QPointer ShowForwardMessagesBox( MessageIdsList &&items, base::lambda_once &&successCallback) { const auto weak = std::make_shared>(); @@ -493,6 +493,7 @@ void ShowForwardMessagesBox( *weak = Ui::show(Box( std::make_unique(std::move(callback)), std::move(initBox)), LayerOption::KeepOther); + return weak->data(); } void PeerMenuAddChannelMembers(not_null channel) { diff --git a/Telegram/SourceFiles/window/window_peer_menu.h b/Telegram/SourceFiles/window/window_peer_menu.h index db8e13187..924873cf9 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.h +++ b/Telegram/SourceFiles/window/window_peer_menu.h @@ -20,6 +20,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org */ #pragma once +namespace Ui { +class RpWidget; +} // namespace Ui + namespace Window { class Controller; @@ -48,7 +52,7 @@ void PeerMenuAddChannelMembers(not_null channel); base::lambda ClearHistoryHandler(not_null peer); base::lambda DeleteAndLeaveHandler(not_null peer); -void ShowForwardMessagesBox( +QPointer ShowForwardMessagesBox( MessageIdsList &&items, base::lambda_once &&successCallback = nullptr);