mirror of
https://github.com/vale981/tdesktop
synced 2025-03-05 09:41:41 -05:00
Add audio playlist using Info::Media::ListWidget.
This commit is contained in:
parent
63e89ddc9a
commit
5a7d8bcffb
17 changed files with 390 additions and 138 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ¶ms) {
|
||||
return parentController()->showSection(std::move(memento), params);
|
||||
}
|
||||
|
||||
void AbstractController::showBackFromStack(
|
||||
const Window::SectionShow ¶ms) {
|
||||
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 ¶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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ¶ms = Window::SectionShow()) override;
|
||||
void showBackFromStack(
|
||||
const Window::SectionShow ¶ms = 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 §ion() 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 ¶ms = Window::SectionShow()) override;
|
||||
void showBackFromStack(
|
||||
const Window::SectionShow ¶ms = 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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -234,7 +234,7 @@ Cover::Cover(
|
|||
, _peer(peer)
|
||||
, _userpic(
|
||||
this,
|
||||
controller->window(),
|
||||
controller->parentController(),
|
||||
_peer,
|
||||
Ui::UserpicButton::Role::OpenPhoto,
|
||||
st::infoProfilePhoto)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -226,7 +226,7 @@ mediaPlayerPanelVolumeToggleTop: 57px;
|
|||
|
||||
mediaPlayerScroll: ScrollArea(defaultSolidScroll) {
|
||||
deltat: 10px;
|
||||
deltab: 0px;
|
||||
deltab: 10px;
|
||||
}
|
||||
mediaPlayerListHeightMax: 280px;
|
||||
mediaPlayerListMarginBottom: 10px;
|
||||
|
|
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue