Add sample PiP controls.

This commit is contained in:
John Preston 2020-01-28 14:48:29 +03:00
parent 63090fb75f
commit b88219902f
7 changed files with 142 additions and 47 deletions

View File

@ -2317,6 +2317,12 @@ void OverlayWidget::playbackControlsFromFullScreen() {
playbackToggleFullScreen();
}
void OverlayWidget::playbackControlsToPictureInPicture() {
if (!videoIsGifv()) {
switchToPip();
}
}
void OverlayWidget::playbackPauseResume() {
Expects(_streamed != nullptr);
@ -2412,11 +2418,6 @@ void OverlayWidget::switchToPip() {
void OverlayWidget::playbackToggleFullScreen() {
Expects(_streamed != nullptr);
if (!videoIsGifv() && !_fullScreenVideo) {
switchToPip();
return;
}
if (!videoShown() || (videoIsGifv() && !_fullScreenVideo)) {
return;
}

View File

@ -174,6 +174,7 @@ private:
float64 playbackControlsCurrentVolume() override;
void playbackControlsToFullScreen() override;
void playbackControlsFromFullScreen() override;
void playbackControlsToPictureInPicture() override;
void playbackPauseResume();
void playbackToggleFullScreen();
void playbackPauseOnCall();

View File

@ -10,11 +10,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/streaming/media_streaming_player.h"
#include "media/streaming/media_streaming_document.h"
#include "media/streaming/media_streaming_utility.h"
#include "media/audio/media_audio.h"
#include "core/application.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/widgets/buttons.h"
#include "ui/wrap/fade_wrap.h"
#include "window/window_controller.h"
#include "styles/style_window.h"
#include "styles/style_mediaview.h"
#include "styles/style_layers.h" // st::boxTitleClose
#include <QtGui/QWindow>
#include <QtGui/QScreen>
@ -564,16 +568,6 @@ void PipPanel::moveAnimated(QPoint to) {
anim::easeOutCirc);
}
void PipPanel::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Space) {
//playbackPauseResume();
} else if (e->key() == Qt::Key_Escape) {
//crl::on_main(this, [=] {
// _closeAndContinue();
//});
}
}
Pip::Pip(
QWidget *parent,
std::shared_ptr<Streaming::Document> document,
@ -583,8 +577,32 @@ Pip::Pip(
, _panel(parent, [=](QPainter &p, const FrameRequest &request) {
paint(p, request);
})
, _playPauseResume(
std::in_place,
&_panel,
object_ptr<Ui::IconButton>(&_panel, st::mediaviewPlayButton))
, _pictureInPicture(
std::in_place,
&_panel,
object_ptr<Ui::IconButton>(&_panel, st::mediaviewFullScreenButton))
, _close(
std::in_place,
&_panel,
object_ptr<Ui::IconButton>(&_panel, st::boxTitleClose))
, _closeAndContinue(std::move(closeAndContinue))
, _destroy(std::move(destroy)) {
_close->entity()->addClickHandler([=] {
_panel.close();
});
_pictureInPicture->entity()->addClickHandler([=] {
_closeAndContinue();
});
_playPauseResume->entity()->addClickHandler([=] {
playbackPauseResume();
});
_close->show(anim::type::instant);
_pictureInPicture->show(anim::type::instant);
_playPauseResume->show(anim::type::instant);
setupPanel();
setupStreaming();
}
@ -597,13 +615,35 @@ void Pip::setupPanel() {
_panel.setAspectRatio(size);
}
_panel.setPosition(PipPanel::Position());
//_panel.events(
//) | rpl::filter([=](not_null<QEvent*> e) {
// return (e->type() == QEvent::WindowActivate);
//}) | rpl::start_with_next([=](not_null<QEvent*> e) {
// int a = 0;
//}, _panel.lifetime());
_panel.show();
_panel.sizeValue(
) | rpl::start_with_next([=](QSize size) {
_close->moveToLeft(0, 0, size.width());
const auto skip = st::mediaviewFullScreenLeft;
const auto sum = _playPauseResume->width() + skip + _pictureInPicture->width();
const auto left = (size.width() - sum) / 2;
const auto top = size.height() - _playPauseResume->height() - skip;
_playPauseResume->moveToLeft(left, top);
_pictureInPicture->moveToRight(left, top);
}, _panel.lifetime());
_panel.events(
) | rpl::filter([=](not_null<QEvent*> e) {
return e->type() == QEvent::Close;
}) | rpl::start_with_next([=] {
_destroy();
}, _panel.lifetime());
}
void Pip::updatePlayPauseResumeState(const Player::TrackState &state) {
auto showPause = Player::ShowPauseIcon(state.state);
if (showPause != _showPause) {
_showPause = showPause;
_playPauseResume->entity()->setIconOverride(
_showPause ? &st::mediaviewPauseIcon : nullptr,
_showPause ? &st::mediaviewPauseIconOver : nullptr);
}
}
void Pip::setupStreaming() {
@ -632,39 +672,59 @@ void Pip::handleStreamingUpdate(Streaming::Update &&update) {
update.data.match([&](Information &update) {
_panel.setAspectRatio(update.video.size);
}, [&](const PreloadedVideo &update) {
//updatePlaybackState();
updatePlaybackState();
}, [&](const UpdateVideo &update) {
_panel.update();
Core::App().updateNonIdle();
//updatePlaybackState();
updatePlaybackState();
}, [&](const PreloadedAudio &update) {
//updatePlaybackState();
updatePlaybackState();
}, [&](const UpdateAudio &update) {
//updatePlaybackState();
updatePlaybackState();
}, [&](WaitingForData) {
}, [&](MutedByOther) {
}, [&](Finished) {
//updatePlaybackState();
updatePlaybackState();
});
}
void Pip::updatePlaybackState() {
const auto state = _instance.player().prepareLegacyState();
if (state.position != kTimeUnknown && state.length != kTimeUnknown) {
updatePlayPauseResumeState(state);
}
}
void Pip::handleStreamingError(Streaming::Error &&error) {
_panel.close();
}
void Pip::playbackPauseResume() {
if (_instance.player().finished() || !_instance.player().active()) {
//restartAtSeekPosition(0);
if (_instance.player().failed()) {
_panel.close();
} else if (_instance.player().finished()
|| !_instance.player().active()) {
restartAtSeekPosition(0);
} else if (_instance.player().paused()) {
_instance.resume();
//updatePlaybackState();
//playbackPauseMusic();
updatePlaybackState();
} else {
_instance.pause();
//updatePlaybackState();
updatePlaybackState();
}
}
void Pip::restartAtSeekPosition(crl::time position) {
if (!_instance.info().video.cover.isNull()) {
_instance.saveFrameToCover();
}
auto options = Streaming::PlaybackOptions();
options.position = position;
options.audioId = _instance.player().prepareLegacyState().id;
_instance.play(options);
updatePlaybackState();
}
QImage Pip::videoFrame(const FrameRequest &request) const {
if (_instance.player().ready()) {
return _instance.frame(request);

View File

@ -13,7 +13,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QPointer>
namespace Ui {
class IconButton;
template <typename Widget>
class FadeWrap;
} // namespace Ui
namespace Media {
namespace Player {
struct TrackState;
} // namespace Player
namespace View {
#if defined Q_OS_MAC && !defined OS_MAC_OLD
@ -49,7 +59,6 @@ protected:
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void keyPressEvent(QKeyEvent *e) override;
private:
void setPositionDefault();
@ -97,6 +106,10 @@ private:
void handleStreamingUpdate(Streaming::Update &&update);
void handleStreamingError(Streaming::Error &&error);
void updatePlaybackState();
void updatePlayPauseResumeState(const Player::TrackState &state);
void restartAtSeekPosition(crl::time position);
[[nodiscard]] QImage videoFrame(const FrameRequest &request) const;
[[nodiscard]] QImage videoFrameForDirectPaint(
const FrameRequest &request) const;
@ -105,6 +118,11 @@ private:
PipPanel _panel;
QSize _size;
base::unique_qptr<Ui::FadeWrap<Ui::IconButton>> _playPauseResume;
base::unique_qptr< Ui::FadeWrap<Ui::IconButton>> _pictureInPicture;
base::unique_qptr< Ui::FadeWrap<Ui::IconButton>> _close;
bool _showPause = false;
FnMut<void()> _closeAndContinue;
FnMut<void()> _destroy;

View File

@ -31,6 +31,7 @@ PlaybackControls::PlaybackControls(
, _playbackProgress(std::make_unique<PlaybackProgress>())
, _volumeController(this, st::mediaviewPlayback)
, _fullScreenToggle(this, st::mediaviewFullScreenButton)
, _pictureInPicture(this, st::mediaviewFullScreenButton)
, _playedAlready(this, st::mediaviewPlayProgressLabel)
, _toPlayLeft(this, st::mediaviewPlayProgressLabel)
, _fadeAnimation(std::make_unique<Ui::FadeAnimation>(this)) {
@ -42,6 +43,13 @@ PlaybackControls::PlaybackControls(
fadeUpdated(opacity);
});
_pictureInPicture->setIconOverride(
&st::mediaviewFullScreenOutIcon,
&st::mediaviewFullScreenOutIconOver);
_pictureInPicture->addClickHandler([=] {
_delegate->playbackControlsToPictureInPicture();
});
_volumeController->setValue(_delegate->playbackControlsCurrentVolume());
_volumeController->setChangeProgressCallback([=](float64 value) {
_delegate->playbackControlsVolumeChanged(value);
@ -275,26 +283,31 @@ void PlaybackControls::setInFullScreen(bool inFullScreen) {
}
void PlaybackControls::resizeEvent(QResizeEvent *e) {
int playTop = (height() - _playPauseResume->height()) / 2;
_playPauseResume->moveToLeft(st::mediaviewPlayPauseLeft, playTop);
const auto skip = st::mediaviewFullScreenLeft;
int fullScreenTop = (height() - _fullScreenToggle->height()) / 2;
_fullScreenToggle->moveToRight(st::mediaviewFullScreenLeft, fullScreenTop);
_volumeController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
_volumeController->moveToRight(st::mediaviewFullScreenLeft + _fullScreenToggle->width() + st::mediaviewVolumeLeft, st::mediaviewPlaybackTop);
auto playbackWidth = width() - st::mediaviewPlayPauseLeft - _playPauseResume->width() - playTop - fullScreenTop - _volumeController->width() - st::mediaviewVolumeLeft - _fullScreenToggle->width() - st::mediaviewFullScreenLeft;
auto playbackWidth = width() - 2 * skip;
_playbackSlider->resize(playbackWidth, st::mediaviewPlayback.seekSize.height());
_playbackSlider->moveToLeft(st::mediaviewPlayPauseLeft + _playPauseResume->width() + playTop, st::mediaviewPlaybackTop);
_playedAlready->moveToLeft(st::mediaviewPlayPauseLeft + _playPauseResume->width() + playTop, st::mediaviewPlayProgressTop);
_toPlayLeft->moveToRight(width() - (st::mediaviewPlayPauseLeft + _playPauseResume->width() + playTop) - playbackWidth, st::mediaviewPlayProgressTop);
_playbackSlider->moveToLeft(st::mediaviewPlayPauseLeft, st::mediaviewPlaybackTop);
_playedAlready->moveToLeft(st::mediaviewPlayPauseLeft, st::mediaviewPlayProgressTop);
_toPlayLeft->moveToRight(st::mediaviewPlayPauseLeft, st::mediaviewPlayProgressTop);
if (_downloadProgress) {
const auto left = (_playbackSlider->width() - _downloadProgress->width()) / 2;
_downloadProgress->move(_playbackSlider->x() + left, st::mediaviewPlayProgressTop);
}
auto left = skip;
const auto playTop = height() - _playPauseResume->height() - skip;
_playPauseResume->moveToLeft(left, playTop);
left += _playPauseResume->width() + skip;
_fullScreenToggle->moveToLeft(left, playTop);
left += _fullScreenToggle->width() + skip;
_pictureInPicture->moveToLeft(left, playTop);
_volumeController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
_volumeController->moveToRight(skip, playTop + (_fullScreenToggle->height() - _volumeController->height()) / 2);
}
void PlaybackControls::paintEvent(QPaintEvent *e) {

View File

@ -38,6 +38,7 @@ public:
[[nodiscard]] virtual float64 playbackControlsCurrentVolume() = 0;
virtual void playbackControlsToFullScreen() = 0;
virtual void playbackControlsFromFullScreen() = 0;
virtual void playbackControlsToPictureInPicture() = 0;
};
PlaybackControls(QWidget *parent, not_null<Delegate*> delegate);
@ -90,6 +91,7 @@ private:
std::unique_ptr<PlaybackProgress> _receivedTillProgress;
object_ptr<Ui::MediaSlider> _volumeController;
object_ptr<Ui::IconButton> _fullScreenToggle;
object_ptr<Ui::IconButton> _pictureInPicture;
object_ptr<Ui::LabelSimple> _playedAlready;
object_ptr<Ui::LabelSimple> _toPlayLeft;
object_ptr<Ui::LabelSimple> _downloadProgress = { nullptr };

View File

@ -24,7 +24,7 @@ mediaviewPlayback: MediaSlider {
duration: mediaviewOverDuration;
}
mediaviewControllerSize: size(600px, 50px);
mediaviewControllerSize: size(480px, 100px);
mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) {
font: semiboldFont;
textFg: mediaviewPlaybackProgressFg;
@ -57,7 +57,7 @@ mediaviewFullScreenOutIconOver: icon {{ "media_fullscreen_from", mediaviewPlayba
mediaviewPlaybackTop: 28px;
mediaviewVolumeWidth: 60px;
mediaviewControllerRadius: 25px;
mediaviewControllerRadius: roundRadiusLarge;
mediaviewLeft: icon {{ "mediaview_next-flip_horizontal", mediaviewControlFg }};
mediaviewRight: icon {{ "mediaview_next", mediaviewControlFg }};