Add audio playlist using Info::Media::ListWidget.

This commit is contained in:
John Preston 2017-12-09 19:13:06 +04:00
parent 63e89ddc9a
commit 5a7d8bcffb
17 changed files with 390 additions and 138 deletions

View File

@ -1148,12 +1148,12 @@ void HistoryDocument::initDimensions() {
if (thumbed) { if (thumbed) {
_minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom(); _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom();
if (!captioned && (_parent->Has<HistoryMessageSigned>() || _parent->Has<HistoryMessageEdited>())) {
_minh += st::msgDateFont->height - st::msgDateDelta.y();
}
} else { } else {
_minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom(); _minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
} }
if (!captioned && (_parent->Has<HistoryMessageSigned>() || _parent->Has<HistoryMessageEdited>())) {
_minh += st::msgDateFont->height - st::msgDateDelta.y();
}
if (!isBubbleTop()) { if (!isBubbleTop()) {
_minh -= st::msgFileTopMinus; _minh -= st::msgFileTopMinus;
} }

View File

@ -165,7 +165,7 @@ void ListController::restoreState(
} }
void ListController::rowClicked(not_null<PeerListRow*> row) { void ListController::rowClicked(not_null<PeerListRow*> row) {
_controller->window()->showPeerHistory( _controller->parentController()->showPeerHistory(
row->peer(), row->peer(),
Window::SectionShow::Way::Forward); Window::SectionShow::Way::Forward);
} }

View File

@ -44,16 +44,46 @@ not_null<PeerData*> CorrectPeer(PeerId peerId) {
} // namespace } // namespace
rpl::producer<SparseIdsMergedSlice> AbstractController::mediaSource(
SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore,
int limitAfter) const {
return SharedMediaMergedViewer(
SharedMediaMergedKey(
SparseIdsMergedSlice::Key(
peerId(),
migratedPeerId(),
aroundId),
section().mediaType()),
limitBefore,
limitAfter);
}
rpl::producer<QString> AbstractController::mediaSourceQueryValue() const {
return rpl::single(QString());
}
void AbstractController::showSection(
Window::SectionMemento &&memento,
const Window::SectionShow &params) {
return parentController()->showSection(std::move(memento), params);
}
void AbstractController::showBackFromStack(
const Window::SectionShow &params) {
return parentController()->showBackFromStack(params);
}
Controller::Controller( Controller::Controller(
not_null<WrapWidget*> widget, not_null<WrapWidget*> widget,
not_null<Window::Controller*> window, not_null<Window::Controller*> window,
not_null<ContentMemento*> memento) not_null<ContentMemento*> memento)
: _widget(widget) : AbstractController(window)
, _widget(widget)
, _peer(App::peer(memento->peerId())) , _peer(App::peer(memento->peerId()))
, _migrated(memento->migratedPeerId() , _migrated(memento->migratedPeerId()
? App::peer(memento->migratedPeerId()) ? App::peer(memento->migratedPeerId())
: nullptr) : nullptr)
, _window(window)
, _section(memento->section()) { , _section(memento->section()) {
updateSearchControllers(memento); updateSearchControllers(memento);
setupMigrationViewer(); setupMigrationViewer();
@ -66,11 +96,11 @@ void Controller::setupMigrationViewer() {
Notify::PeerUpdateValue(_peer, Notify::PeerUpdate::Flag::MigrationChanged) Notify::PeerUpdateValue(_peer, Notify::PeerUpdate::Flag::MigrationChanged)
| rpl::start_with_next([this] { | rpl::start_with_next([this] {
if (_peer->migrateTo() || (_peer->migrateFrom() != _migrated)) { if (_peer->migrateTo() || (_peer->migrateFrom() != _migrated)) {
auto windowController = window(); auto window = parentController();
auto peerId = _peer->id; auto peerId = _peer->id;
auto section = _section; auto section = _section;
InvokeQueued(_widget, [=] { InvokeQueued(_widget, [=] {
windowController->showSection( window->showSection(
Memento(peerId, section), Memento(peerId, section),
Window::SectionShow( Window::SectionShow(
Window::SectionShow::Way::Backward, Window::SectionShow::Way::Backward,
@ -162,13 +192,13 @@ void Controller::showSection(
Window::SectionMemento &&memento, Window::SectionMemento &&memento,
const Window::SectionShow &params) { const Window::SectionShow &params) {
if (!_widget->showInternal(&memento, params)) { if (!_widget->showInternal(&memento, params)) {
_window->showSection(std::move(memento), params); AbstractController::showSection(std::move(memento), params);
} }
} }
void Controller::showBackFromStack(const Window::SectionShow &params) { void Controller::showBackFromStack(const Window::SectionShow &params) {
if (!_widget->showBackFromStackInternal(params)) { if (!_widget->showBackFromStackInternal(params)) {
_window->showBackFromStack(params); AbstractController::showBackFromStack(params);
} }
} }

View File

@ -67,26 +67,62 @@ private:
}; };
class Controller : public Window::Navigation { class AbstractController : public Window::Navigation {
public:
AbstractController(not_null<Window::Controller*> parent)
: _parent(parent) {
}
virtual not_null<PeerData*> 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<SparseIdsMergedSlice> mediaSource(
SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore,
int limitAfter) const;
virtual rpl::producer<QString> mediaSourceQueryValue() const;
void showSection(
Window::SectionMemento &&memento,
const Window::SectionShow &params = Window::SectionShow()) override;
void showBackFromStack(
const Window::SectionShow &params = Window::SectionShow()) override;
not_null<Window::Controller*> parentController() override {
return _parent;
}
private:
not_null<Window::Controller*> _parent;
};
class Controller : public AbstractController {
public: public:
Controller( Controller(
not_null<WrapWidget*> widget, not_null<WrapWidget*> widget,
not_null<Window::Controller*> window, not_null<Window::Controller*> window,
not_null<ContentMemento*> memento); not_null<ContentMemento*> memento);
not_null<PeerData*> peer() const { not_null<PeerData*> peer() const override {
return _peer; return _peer;
} }
PeerData *migrated() const { PeerData *migrated() const override {
return _migrated; return _migrated;
} }
PeerId peerId() const { Section section() const override {
return _peer->id;
}
PeerId migratedPeerId() const {
return _migrated ? _migrated->id : PeerId(0);
}
const Section &section() const {
return _section; return _section;
} }
@ -97,21 +133,18 @@ public:
rpl::producer<Wrap> wrapValue() const; rpl::producer<Wrap> wrapValue() const;
void setSection(not_null<ContentMemento*> memento); void setSection(not_null<ContentMemento*> memento);
not_null<Window::Controller*> window() const {
return _window;
}
Ui::SearchFieldController *searchFieldController() const { Ui::SearchFieldController *searchFieldController() const {
return _searchFieldController.get(); return _searchFieldController.get();
} }
void setSearchEnabledByContent(bool enabled) { void setSearchEnabledByContent(bool enabled) override {
_seachEnabledByContent = enabled; _seachEnabledByContent = enabled;
} }
rpl::producer<bool> searchEnabledByContent() const; rpl::producer<bool> searchEnabledByContent() const;
rpl::producer<SparseIdsMergedSlice> mediaSource( rpl::producer<SparseIdsMergedSlice> mediaSource(
SparseIdsMergedSlice::UniversalMsgId aroundId, SparseIdsMergedSlice::UniversalMsgId aroundId,
int limitBefore, int limitBefore,
int limitAfter) const; int limitAfter) const override;
rpl::producer<QString> mediaSourceQueryValue() const; rpl::producer<QString> mediaSourceQueryValue() const override;
bool takeSearchStartsFocused() { bool takeSearchStartsFocused() {
return base::take(_searchStartsFocused); return base::take(_searchStartsFocused);
} }
@ -123,9 +156,6 @@ public:
const Window::SectionShow &params = Window::SectionShow()) override; const Window::SectionShow &params = Window::SectionShow()) override;
void showBackFromStack( void showBackFromStack(
const Window::SectionShow &params = Window::SectionShow()) override; const Window::SectionShow &params = Window::SectionShow()) override;
not_null<Window::Controller*> parentController() override {
return _window;
}
rpl::lifetime &lifetime() { rpl::lifetime &lifetime() {
return _lifetime; return _lifetime;
@ -143,7 +173,6 @@ private:
not_null<WrapWidget*> _widget; not_null<WrapWidget*> _widget;
not_null<PeerData*> _peer; not_null<PeerData*> _peer;
PeerData *_migrated = nullptr; PeerData *_migrated = nullptr;
not_null<Window::Controller*> _window;
rpl::variable<Wrap> _wrap; rpl::variable<Wrap> _wrap;
Section _section; Section _section;

View File

@ -116,7 +116,7 @@ void WrapWidget::startInjectingActivePeerProfiles() {
using namespace rpl::mappers; using namespace rpl::mappers;
rpl::combine( rpl::combine(
_wrap.value(), _wrap.value(),
_controller->window()->activePeer.value()) _controller->parentController()->activePeer.value())
| rpl::filter((_1 == Wrap::Side) && (_2 != nullptr)) | rpl::filter((_1 == Wrap::Side) && (_2 != nullptr))
| rpl::map(_2) | rpl::map(_2)
| rpl::start_with_next([this](not_null<PeerData*> peer) { | rpl::start_with_next([this](not_null<PeerData*> peer) {
@ -241,7 +241,7 @@ void WrapWidget::forceContentRepaint() {
// _anotherTabMemento = createTabMemento(tab); // _anotherTabMemento = createTabMemento(tab);
// } // }
// auto newController = createController( // auto newController = createController(
// _controller->window(), // _controller->parentController(),
// _anotherTabMemento.get()); // _anotherTabMemento.get());
// auto newContent = createContent( // auto newContent = createContent(
// _anotherTabMemento.get(), // _anotherTabMemento.get(),
@ -331,7 +331,7 @@ void WrapWidget::createTopBar() {
_topBar, _topBar,
st::infoTopBarClose)); st::infoTopBarClose));
close->addClickHandler([this] { close->addClickHandler([this] {
_controller->window()->closeThirdSection(); _controller->parentController()->closeThirdSection();
}); });
} }
if (wrapValue == Wrap::Layer) { if (wrapValue == Wrap::Layer) {
@ -340,7 +340,7 @@ void WrapWidget::createTopBar() {
_topBar, _topBar,
st::infoLayerTopBarClose)); st::infoLayerTopBarClose));
close->addClickHandler([this] { close->addClickHandler([this] {
_controller->window()->hideSpecialLayer(); _controller->parentController()->hideSpecialLayer();
}); });
} else if (requireTopBarSearch()) { } else if (requireTopBarSearch()) {
auto search = _controller->searchFieldController(); auto search = _controller->searchFieldController();
@ -465,7 +465,7 @@ void WrapWidget::showProfileMenu() {
_topBarMenuToggle->installEventFilter(_topBarMenu.get()); _topBarMenuToggle->installEventFilter(_topBarMenu.get());
Window::FillPeerMenu( Window::FillPeerMenu(
_controller->window(), _controller->parentController(),
_controller->peer(), _controller->peer(),
[this](const QString &text, base::lambda<void()> callback) { [this](const QString &text, base::lambda<void()> callback) {
return _topBarMenu->addAction(text, std::move(callback)); return _topBarMenu->addAction(text, std::move(callback));
@ -788,7 +788,7 @@ void WrapWidget::showNewContent(
&& (params.animated != anim::type::instant); && (params.animated != anim::type::instant);
auto animationParams = SectionSlideParams(); auto animationParams = SectionSlideParams();
auto newController = createController( auto newController = createController(
_controller->window(), _controller->parentController(),
memento); memento);
auto newContent = object_ptr<ContentWidget>(nullptr); auto newContent = object_ptr<ContentWidget>(nullptr);
if (needAnimation) { if (needAnimation) {

View File

@ -35,6 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "window/main_window.h" #include "window/main_window.h"
#include "styles/style_overview.h" #include "styles/style_overview.h"
#include "styles/style_info.h" #include "styles/style_info.h"
#include "media/player/media_player_instance.h"
#include "boxes/peer_list_controllers.h" #include "boxes/peer_list_controllers.h"
#include "boxes/confirm_box.h" #include "boxes/confirm_box.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
@ -546,7 +547,7 @@ void ListWidget::Section::refreshHeight() {
ListWidget::ListWidget( ListWidget::ListWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller) not_null<AbstractController*> controller)
: RpWidget(parent) : RpWidget(parent)
, _controller(controller) , _controller(controller)
, _peer(_controller->peer()) , _peer(_controller->peer())
@ -594,6 +595,18 @@ rpl::producer<SelectedItems> ListWidget::selectedListValue() const {
collectSelectedItems()); 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() { void ListWidget::restart() {
mouseActionCancel(); mouseActionCancel();
@ -1347,6 +1360,7 @@ void ListWidget::showContextMenu(
_contextMenu = nullptr; _contextMenu = nullptr;
mouseActionUpdate(QCursor::pos()); mouseActionUpdate(QCursor::pos());
repaintItem(universalId); repaintItem(universalId);
_checkForHide.fire({});
})); }));
_contextMenu->popup(e->globalPos()); _contextMenu->popup(e->globalPos());
e->accept(); e->accept();
@ -1373,12 +1387,14 @@ void ListWidget::forwardItem(UniversalMsgId universalId) {
} }
void ListWidget::forwardItems(MessageIdsList &&items) { void ListWidget::forwardItems(MessageIdsList &&items) {
const auto weak = make_weak(this); auto callback = [weak = make_weak(this)] {
Window::ShowForwardMessagesBox(std::move(items), [weak] {
if (const auto strong = weak.data()) { if (const auto strong = weak.data()) {
strong->clearSelected(); strong->clearSelected();
} }
}); };
setActionBoxWeak(Window::ShowForwardMessagesBox(
std::move(items),
std::move(callback)));
} }
void ListWidget::deleteSelected() { void ListWidget::deleteSelected() {
@ -1393,7 +1409,19 @@ void ListWidget::deleteItem(UniversalMsgId universalId) {
void ListWidget::deleteItems(MessageIdsList &&items) { void ListWidget::deleteItems(MessageIdsList &&items) {
if (!items.empty()) { if (!items.empty()) {
Ui::show(Box<DeleteMessagesBox>(std::move(items))); const auto box = Ui::show(Box<DeleteMessagesBox>(std::move(items)));
setActionBoxWeak(box.data());
}
}
void ListWidget::setActionBoxWeak(QPointer<Ui::RpWidget> 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; auto pressLayout = _overLayout;
_mouseAction = MouseAction::None; _mouseAction = MouseAction::None;
_pressWasInactive = _controller->window()->window()->wasInactivePress(); _pressWasInactive = _controller->parentController()->window()->wasInactivePress();
if (_pressWasInactive) _controller->window()->window()->setInactivePress(false); if (_pressWasInactive) _controller->parentController()->window()->setInactivePress(false);
if (ClickHandler::getPressed() && !hasSelected()) { if (ClickHandler::getPressed() && !hasSelected()) {
_mouseAction = MouseAction::PrepareDrag; _mouseAction = MouseAction::PrepareDrag;
@ -1893,7 +1921,7 @@ void ListWidget::performDrag() {
// mimeData->setData(qsl("application/x-td-forward-selected"), "1"); // mimeData->setData(qsl("application/x-td-forward-selected"), "1");
// } // }
// } // }
// _controller->window()->launchDrag(std::move(mimeData)); // _controller->parentController()->window()->launchDrag(std::move(mimeData));
// return; // return;
//} else { //} else {
// auto forwardMimeType = QString(); // auto forwardMimeType = QString();
@ -1924,7 +1952,7 @@ void ListWidget::performDrag() {
// } // }
// // This call enters event loop and can destroy any QObject. // // This call enters event loop and can destroy any QObject.
// _controller->window()->launchDrag(std::move(mimeData)); // _controller->parentController()->window()->launchDrag(std::move(mimeData));
// return; // return;
// } // }
//} //}
@ -1974,7 +2002,7 @@ void ListWidget::mouseActionFinish(const QPoint &screenPos, Qt::MouseButton butt
if (selection.text != FullSelection if (selection.text != FullSelection
&& selection.text.from == selection.text.to) { && selection.text.from == selection.text.to) {
clearSelected(); clearSelected();
//_controller->window()->setInnerFocus(); // #TODO focus //_controller->parentController()->window()->setInnerFocus(); // #TODO focus
} }
} }
} }

View File

@ -40,7 +40,7 @@ class Controller;
namespace Info { namespace Info {
class Controller; class AbstractController;
namespace Media { namespace Media {
@ -51,7 +51,7 @@ class ListWidget : public Ui::RpWidget {
public: public:
ListWidget( ListWidget(
QWidget *parent, QWidget *parent,
not_null<Controller*> controller); not_null<AbstractController*> controller);
void restart(); void restart();
@ -61,6 +61,14 @@ public:
clearSelected(); clearSelected();
} }
QRect getCurrentSongGeometry();
rpl::producer<> checkForHide() const {
return _checkForHide.events();
}
bool preventAutoHide() const {
return (_contextMenu != nullptr) || (_actionBoxWeak != nullptr);
}
void saveState(not_null<Memento*> memento); void saveState(not_null<Memento*> memento);
void restoreState(not_null<Memento*> memento); void restoreState(not_null<Memento*> memento);
@ -259,7 +267,9 @@ private:
void validateTrippleClickStartTime(); void validateTrippleClickStartTime();
void checkMoveToOtherViewer(); void checkMoveToOtherViewer();
const not_null<Controller*> _controller; void setActionBoxWeak(QPointer<Ui::RpWidget> box);
const not_null<AbstractController*> _controller;
const not_null<PeerData*> _peer; const not_null<PeerData*> _peer;
PeerData * const _migrated = nullptr; PeerData * const _migrated = nullptr;
Type _type = Type::Photo; Type _type = Type::Photo;
@ -294,7 +304,11 @@ private:
style::cursor _cursor = style::cur_default; style::cursor _cursor = style::cur_default;
DragSelectAction _dragSelectAction = DragSelectAction::None; DragSelectAction _dragSelectAction = DragSelectAction::None;
bool _wasSelectedText = false; // was some text selected in current drag action bool _wasSelectedText = false; // was some text selected in current drag action
Ui::PopupMenu *_contextMenu = nullptr; Ui::PopupMenu *_contextMenu = nullptr;
rpl::event_stream<> _checkForHide;
QPointer<Ui::RpWidget> _actionBoxWeak;
rpl::lifetime _actionBoxWeakLifetime;
QPoint _trippleClickPoint; QPoint _trippleClickPoint;
TimeMs _trippleClickStartTime = 0; TimeMs _trippleClickStartTime = 0;

View File

@ -325,7 +325,7 @@ Ui::MultiSlideTracker DetailsFiller::fillUserButtons(
using namespace rpl::mappers; using namespace rpl::mappers;
Ui::MultiSlideTracker tracker; Ui::MultiSlideTracker tracker;
auto window = _controller->window(); auto window = _controller->parentController();
auto addSendMessageButton = [&] { auto addSendMessageButton = [&] {
auto sendMessageVisible = rpl::combine( auto sendMessageVisible = rpl::combine(
@ -377,7 +377,7 @@ Ui::MultiSlideTracker DetailsFiller::fillChannelButtons(
using namespace rpl::mappers; using namespace rpl::mappers;
Ui::MultiSlideTracker tracker; Ui::MultiSlideTracker tracker;
auto window = _controller->window(); auto window = _controller->parentController();
auto viewChannelVisible = rpl::combine( auto viewChannelVisible = rpl::combine(
_controller->wrapValue(), _controller->wrapValue(),
window->historyPeer.value(), window->historyPeer.value(),

View File

@ -234,7 +234,7 @@ Cover::Cover(
, _peer(peer) , _peer(peer)
, _userpic( , _userpic(
this, this,
controller->window(), controller->parentController(),
_peer, _peer,
Ui::UserpicButton::Role::OpenPhoto, Ui::UserpicButton::Role::OpenPhoto,
st::infoProfilePhoto) st::infoProfilePhoto)

View File

@ -74,7 +74,7 @@ Members::Members(
| rpl::start_with_next([this](int count) { | rpl::start_with_next([this](int count) {
const auto enabled = (count >= kEnableSearchMembersAfterCount); const auto enabled = (count >= kEnableSearchMembersAfterCount);
_controller->setSearchEnabledByContent(enabled); _controller->setSearchEnabledByContent(enabled);
}); }, lifetime());
} }
int Members::desiredHeight() const { int Members::desiredHeight() const {

View File

@ -198,8 +198,11 @@ MainWidget::MainWidget(
, _sideShadow(this) , _sideShadow(this)
, _dialogs(this, _controller) , _dialogs(this, _controller)
, _history(this, _controller) , _history(this, _controller)
, _playerPlaylist(this, Media::Player::Panel::Layout::OnlyPlaylist) , _playerPlaylist(
, _playerPanel(this, Media::Player::Panel::Layout::Full) { 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()->setUpdatesHandler(rpcDone(&MainWidget::updateReceived));
Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail)); Messenger::Instance().mtp()->setGlobalFailHandler(rpcFail(&MainWidget::updateFail));

View File

@ -226,7 +226,7 @@ mediaPlayerPanelVolumeToggleTop: 57px;
mediaPlayerScroll: ScrollArea(defaultSolidScroll) { mediaPlayerScroll: ScrollArea(defaultSolidScroll) {
deltat: 10px; deltat: 10px;
deltab: 0px; deltab: 10px;
} }
mediaPlayerListHeightMax: 280px; mediaPlayerListHeightMax: 280px;
mediaPlayerListMarginBottom: 10px; mediaPlayerListMarginBottom: 10px;

View File

@ -199,7 +199,7 @@ auto Instance::playlistKey(not_null<Data*> data) const
-> base::optional<SliceKey> { -> base::optional<SliceKey> {
const auto contextId = data->current.contextId(); const auto contextId = data->current.contextId();
const auto history = data->history; const auto history = data->history;
if (!contextId || !history) { if (!contextId || !history || !IsServerMsgId(contextId.msg)) {
return {}; return {};
} }

View File

@ -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_cover.h"
#include "media/player/media_player_instance.h" #include "media/player/media_player_instance.h"
#include "styles/style_overview.h" #include "info/media/info_media_list_widget.h"
#include "styles/style_widgets.h"
#include "styles/style_media_player.h"
#include "ui/widgets/shadow.h" #include "ui/widgets/shadow.h"
#include "ui/widgets/scroll_area.h" #include "ui/widgets/scroll_area.h"
#include "mainwindow.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 Media {
namespace Player { 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::Controller*> window,
Layout layout)
: RpWidget(parent)
, AbstractController(window)
, _layout(layout) , _layout(layout)
, _showTimer([this] { startShow(); })
, _hideTimer([this] { startHideChecked(); })
, _scroll(this, st::mediaPlayerScroll) { , _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(); hide();
updateSize(); 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())); 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()) { if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
leaveEvent(nullptr); leaveEvent(nullptr);
} }
@ -63,16 +74,36 @@ void Panel::resizeEvent(QResizeEvent *e) {
updateControlsGeometry(); updateControlsGeometry();
} }
void Panel::onListHeightUpdated() { void Panel::listHeightUpdated(int newHeight) {
if (auto widget = _scroll->widget()) { if (newHeight > emptyInnerHeight() || _cover) {
if (widget->height() > 0 || _cover) { updateSize();
updateSize(); } else {
} else { _hideTimer.callOnce(0);
hideIgnoringEnterEvents();
}
} }
} }
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<ListWidget*>(_scroll->widget())) {
return list->preventAutoHide();
}
return false;
}
void Panel::updateControlsGeometry() { void Panel::updateControlsGeometry() {
auto scrollTop = contentTop(); auto scrollTop = contentTop();
auto width = contentWidth(); auto width = contentWidth();
@ -91,7 +122,6 @@ void Panel::updateControlsGeometry() {
} }
if (auto widget = static_cast<TWidget*>(_scroll->widget())) { if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
widget->resizeToWidth(width); widget->resizeToWidth(width);
onScroll();
} }
} }
@ -103,19 +133,9 @@ int Panel::bestPositionFor(int left) const {
} }
void Panel::scrollPlaylistToCurrentTrack() { void Panel::scrollPlaylistToCurrentTrack() {
// #TODO playlist if (const auto list = static_cast<ListWidget*>(_scroll->widget())) {
//if (auto list = static_cast<ListWidget*>(_scroll->widget())) { const auto rect = list->getCurrentSongGeometry();
// auto rect = list->getCurrentTrackGeometry(); _scroll->scrollToY(rect.y() - st::infoMediaMargin.top());
// auto top = _scroll->scrollTop(), bottom = top + _scroll->height();
// _scroll->scrollToY(rect.y());
//}
}
void Panel::onScroll() {
if (auto widget = static_cast<TWidget*>(_scroll->widget())) {
int visibleTop = _scroll->scrollTop();
int visibleBottom = visibleTop + _scroll->height();
widget->setVisibleTopBottom(visibleTop, visibleBottom);
} }
} }
@ -170,42 +190,45 @@ void Panel::paintEvent(QPaintEvent *e) {
} }
void Panel::enterEventHook(QEvent *e) { void Panel::enterEventHook(QEvent *e) {
if (_ignoringEnterEvents) return; if (_ignoringEnterEvents || contentTooSmall()) return;
_hideTimer.stop(); _hideTimer.cancel();
if (_a_appearance.animating(getms())) { if (_a_appearance.animating(getms())) {
onShowStart(); startShow();
} else { } else {
_showTimer.start(0); _showTimer.callOnce(0);
} }
return TWidget::enterEventHook(e); return TWidget::enterEventHook(e);
} }
void Panel::leaveEventHook(QEvent *e) { void Panel::leaveEventHook(QEvent *e) {
_showTimer.stop(); if (preventAutoHide()) {
return;
}
_showTimer.cancel();
if (_a_appearance.animating(getms())) { if (_a_appearance.animating(getms())) {
onHideStart(); startHide();
} else { } else {
_hideTimer.start(300); _hideTimer.callOnce(300);
} }
return TWidget::leaveEventHook(e); return TWidget::leaveEventHook(e);
} }
void Panel::showFromOther() { void Panel::showFromOther() {
_hideTimer.stop(); _hideTimer.cancel();
if (_a_appearance.animating(getms())) { if (_a_appearance.animating(getms())) {
onShowStart(); startShow();
} else { } else {
_showTimer.start(300); _showTimer.callOnce(300);
} }
} }
void Panel::hideFromOther() { void Panel::hideFromOther() {
_showTimer.stop(); _showTimer.cancel();
if (_a_appearance.animating(getms())) { if (_a_appearance.animating(getms())) {
onHideStart(); startHide();
} else { } else {
_hideTimer.start(0); _hideTimer.callOnce(0);
} }
} }
@ -219,32 +242,108 @@ void Panel::ensureCreated() {
_scrollShadow.create(this, st::mediaPlayerScrollShadow, RectPart::Bottom); _scrollShadow.create(this, st::mediaPlayerScrollShadow, RectPart::Bottom);
} }
// #TODO playlist _refreshListLifetime = instance()->playlistChanges(
//auto list = object_ptr<ListWidget>(this); AudioMsgId::Type::Song
//connect(list, SIGNAL(heightUpdated()), this, SLOT(onListHeightUpdated())); ) | rpl::start_with_next([this] {
//_scroll->setOwnedWidget(std::move(list)); refreshList();
});
refreshList();
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
if (auto window = App::wnd()) { if (const auto window = App::wnd()) {
connect(window->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged())); connect(
window->windowHandle(),
&QWindow::activeChanged,
this,
&Panel::windowActiveChanged);
} }
} }
updateSize();
updateControlsGeometry();
_ignoringEnterEvents = false; _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<QWidget>().destroy();
_listPeer = _listMigratedPeer = nullptr;
}
if (peer && !_listPeer) {
_listPeer = peer;
_listMigratedPeer = migrated;
auto list = object_ptr<ListWidget>(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() { void Panel::performDestroy() {
if (!_scroll->widget()) return; if (!_scroll->widget()) return;
_cover.destroy(); _cover.destroy();
// #TODO playlist _scroll->takeWidget<QWidget>().destroy();
//_scroll->takeWidget<ListWidget>().destroyDelayed(); _listPeer = _listMigratedPeer = nullptr;
_refreshListLifetime.destroy();
if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) { if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
if (auto window = App::wnd()) { if (const auto window = App::wnd()) {
disconnect(window->windowHandle(), SIGNAL(activeChanged()), this, SLOT(onWindowActiveChanged())); disconnect(
window->windowHandle(),
&QWindow::activeChanged,
this,
&Panel::windowActiveChanged);
} }
} }
} }
@ -263,12 +362,22 @@ void Panel::setCloseCallback(ButtonCallback &&callback) {
} }
} }
void Panel::onShowStart() { not_null<PeerData*> 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(); ensureCreated();
if (auto widget = _scroll->widget()) { if (contentTooSmall()) {
if (widget->height() <= 0 && !_cover) { return;
return;
}
} }
if (isHidden()) { if (isHidden()) {
@ -286,11 +395,22 @@ void Panel::hideIgnoringEnterEvents() {
if (isHidden()) { if (isHidden()) {
hideFinished(); hideFinished();
} else { } 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; if (_hiding || isHidden()) return;
_hiding = true; _hiding = true;
@ -340,7 +460,7 @@ int Panel::contentBottom() const {
} }
int Panel::scrollMarginBottom() const { int Panel::scrollMarginBottom() const {
return st::mediaPlayerPanelMarginBottom; return 0;// st::mediaPlayerPanelMarginBottom;
} }
} // namespace Player } // namespace Player

View File

@ -20,6 +20,14 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
#include "base/timer.h"
#include "ui/rp_widget.h"
#include "info/info_controller.h"
namespace Window {
class Controller;
} // namespace Window
namespace Ui { namespace Ui {
class ScrollArea; class ScrollArea;
class Shadow; class Shadow;
@ -30,15 +38,16 @@ namespace Player {
class CoverWidget; class CoverWidget;
class Panel : public TWidget { class Panel : public Ui::RpWidget, private Info::AbstractController {
Q_OBJECT
public: public:
enum class Layout { enum class Layout {
Full, Full,
OnlyPlaylist, OnlyPlaylist,
}; };
Panel(QWidget *parent, Layout layout); Panel(
QWidget *parent,
not_null<Window::Controller*> controller,
Layout layout);
bool overlaps(const QRect &globalRect); bool overlaps(const QRect &globalRect);
@ -59,20 +68,26 @@ protected:
void enterEventHook(QEvent *e) override; void enterEventHook(QEvent *e) override;
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
private slots:
void onShowStart();
void onHideStart();
void onScroll();
void onListHeightUpdated();
void onWindowActiveChanged();
private: private:
// Info::AbstractController implementation.
not_null<PeerData*> 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 ensureCreated();
void performDestroy(); void performDestroy();
void updateControlsGeometry(); void updateControlsGeometry();
void refreshList();
void updateSize(); void updateSize();
void appearanceCallback(); void appearanceCallback();
void hideFinished(); void hideFinished();
@ -90,6 +105,9 @@ private:
void startAnimation(); void startAnimation();
void scrollPlaylistToCurrentTrack(); void scrollPlaylistToCurrentTrack();
not_null<Info::AbstractController*> infoController() {
return static_cast<Info::AbstractController*>(this);
}
Layout _layout; Layout _layout;
bool _hiding = false; bool _hiding = false;
@ -99,13 +117,18 @@ private:
bool _ignoringEnterEvents = false; bool _ignoringEnterEvents = false;
QTimer _hideTimer, _showTimer; base::Timer _showTimer;
base::Timer _hideTimer;
ButtonCallback _pinCallback, _closeCallback; ButtonCallback _pinCallback, _closeCallback;
object_ptr<CoverWidget> _cover = { nullptr }; object_ptr<CoverWidget> _cover = { nullptr };
object_ptr<Ui::ScrollArea> _scroll; object_ptr<Ui::ScrollArea> _scroll;
object_ptr<Ui::Shadow> _scrollShadow = { nullptr }; object_ptr<Ui::Shadow> _scrollShadow = { nullptr };
rpl::lifetime _refreshListLifetime;
PeerData *_listPeer = nullptr;
PeerData *_listMigratedPeer = nullptr;
}; };
} // namespace Clip } // namespace Clip

View File

@ -457,7 +457,7 @@ void PeerMenuShareContactBox(not_null<UserData*> user) {
})); }));
} }
void ShowForwardMessagesBox( QPointer<Ui::RpWidget> ShowForwardMessagesBox(
MessageIdsList &&items, MessageIdsList &&items,
base::lambda_once<void()> &&successCallback) { base::lambda_once<void()> &&successCallback) {
const auto weak = std::make_shared<QPointer<PeerListBox>>(); const auto weak = std::make_shared<QPointer<PeerListBox>>();
@ -493,6 +493,7 @@ void ShowForwardMessagesBox(
*weak = Ui::show(Box<PeerListBox>( *weak = Ui::show(Box<PeerListBox>(
std::make_unique<ChooseRecipientBoxController>(std::move(callback)), std::make_unique<ChooseRecipientBoxController>(std::move(callback)),
std::move(initBox)), LayerOption::KeepOther); std::move(initBox)), LayerOption::KeepOther);
return weak->data();
} }
void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) { void PeerMenuAddChannelMembers(not_null<ChannelData*> channel) {

View File

@ -20,6 +20,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
*/ */
#pragma once #pragma once
namespace Ui {
class RpWidget;
} // namespace Ui
namespace Window { namespace Window {
class Controller; class Controller;
@ -48,7 +52,7 @@ void PeerMenuAddChannelMembers(not_null<ChannelData*> channel);
base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer); base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer);
base::lambda<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer); base::lambda<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer);
void ShowForwardMessagesBox( QPointer<Ui::RpWidget> ShowForwardMessagesBox(
MessageIdsList &&items, MessageIdsList &&items,
base::lambda_once<void()> &&successCallback = nullptr); base::lambda_once<void()> &&successCallback = nullptr);