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) {
_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 {
_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()) {
_minh -= st::msgFileTopMinus;
}

View file

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

View file

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

View file

@ -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<PeerData*> 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<void()> 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<ContentWidget>(nullptr);
if (needAnimation) {

View file

@ -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*> controller)
not_null<AbstractController*> controller)
: RpWidget(parent)
, _controller(controller)
, _peer(_controller->peer())
@ -594,6 +595,18 @@ rpl::producer<SelectedItems> 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<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;
_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
}
}
}

View file

@ -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*> controller);
not_null<AbstractController*> 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*> memento);
void restoreState(not_null<Memento*> memento);
@ -259,7 +267,9 @@ private:
void validateTrippleClickStartTime();
void checkMoveToOtherViewer();
const not_null<Controller*> _controller;
void setActionBoxWeak(QPointer<Ui::RpWidget> box);
const not_null<AbstractController*> _controller;
const not_null<PeerData*> _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<Ui::RpWidget> _actionBoxWeak;
rpl::lifetime _actionBoxWeakLifetime;
QPoint _trippleClickPoint;
TimeMs _trippleClickStartTime = 0;

View file

@ -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(),

View file

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

View file

@ -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 {

View file

@ -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));

View file

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

View file

@ -199,7 +199,7 @@ auto Instance::playlistKey(not_null<Data*> data) const
-> base::optional<SliceKey> {
const auto contextId = data->current.contextId();
const auto history = data->history;
if (!contextId || !history) {
if (!contextId || !history || !IsServerMsgId(contextId.msg)) {
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_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::Controller*> 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<ListWidget*>(_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<TWidget*>(_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<ListWidget*>(_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<TWidget*>(_scroll->widget())) {
int visibleTop = _scroll->scrollTop();
int visibleBottom = visibleTop + _scroll->height();
widget->setVisibleTopBottom(visibleTop, visibleBottom);
if (const auto list = static_cast<ListWidget*>(_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<ListWidget>(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<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() {
if (!_scroll->widget()) return;
_cover.destroy();
// #TODO playlist
//_scroll->takeWidget<ListWidget>().destroyDelayed();
_scroll->takeWidget<QWidget>().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<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();
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

View file

@ -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<Window::Controller*> 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<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 performDestroy();
void updateControlsGeometry();
void refreshList();
void updateSize();
void appearanceCallback();
void hideFinished();
@ -90,6 +105,9 @@ private:
void startAnimation();
void scrollPlaylistToCurrentTrack();
not_null<Info::AbstractController*> infoController() {
return static_cast<Info::AbstractController*>(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<CoverWidget> _cover = { nullptr };
object_ptr<Ui::ScrollArea> _scroll;
object_ptr<Ui::Shadow> _scrollShadow = { nullptr };
rpl::lifetime _refreshListLifetime;
PeerData *_listPeer = nullptr;
PeerData *_listMigratedPeer = nullptr;
};
} // namespace Clip

View file

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

View file

@ -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<ChannelData*> channel);
base::lambda<void()> ClearHistoryHandler(not_null<PeerData*> peer);
base::lambda<void()> DeleteAndLeaveHandler(not_null<PeerData*> peer);
void ShowForwardMessagesBox(
QPointer<Ui::RpWidget> ShowForwardMessagesBox(
MessageIdsList &&items,
base::lambda_once<void()> &&successCallback = nullptr);