Improve design of video player and PiP controls.

This commit is contained in:
John Preston 2020-01-31 12:54:57 +03:00
parent 4d737b35da
commit e889a52f6f
48 changed files with 348 additions and 170 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 659 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

View File

@ -2104,6 +2104,8 @@ bool OverlayWidget::initStreaming(bool continueStreaming) {
|| (!_streamed->instance.player().active() || (!_streamed->instance.player().active()
&& !_streamed->instance.player().finished())) { && !_streamed->instance.player().finished())) {
startStreamingPlayer(); startStreamingPlayer();
} else {
updatePlaybackState();
} }
return true; return true;
} }

View File

@ -20,7 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_controller.h" #include "window/window_controller.h"
#include "styles/style_window.h" #include "styles/style_window.h"
#include "styles/style_mediaview.h" #include "styles/style_mediaview.h"
#include "styles/style_layers.h" // st::boxTitleClose
#include "styles/style_calls.h" // st::callShadow #include "styles/style_calls.h" // st::callShadow
#include <QtGui/QWindow> #include <QtGui/QWindow>
@ -292,6 +291,14 @@ void PipPanel::setPosition(Position position) {
setPositionDefault(); setPositionDefault();
} }
QRect PipPanel::inner() const {
return rect().marginsRemoved(_padding);
}
bool PipPanel::dragging() const {
return _dragState.has_value();
}
rpl::producer<> PipPanel::saveGeometryRequests() const { rpl::producer<> PipPanel::saveGeometryRequests() const {
return _saveGeometryRequests.events(); return _saveGeometryRequests.events();
} }
@ -433,7 +440,7 @@ void PipPanel::paintEvent(QPaintEvent *e) {
} }
auto request = FrameRequest(); auto request = FrameRequest();
const auto inner = rect().marginsRemoved(_padding); const auto inner = this->inner();
request.resize = request.outer = inner.size() * style::DevicePixelRatio(); request.resize = request.outer = inner.size() * style::DevicePixelRatio();
request.corners = RectPart(0) request.corners = RectPart(0)
| ((_attached & (RectPart::Left | RectPart::Top)) | ((_attached & (RectPart::Left | RectPart::Top))
@ -453,7 +460,6 @@ void PipPanel::paintEvent(QPaintEvent *e) {
const auto sides = RectPart::AllSides & ~_attached; const auto sides = RectPart::AllSides & ~_attached;
Ui::Shadow::paint(p, inner, width(), st::callShadow); Ui::Shadow::paint(p, inner, width(), st::callShadow);
} }
p.translate(_padding.left(), _padding.top());
_paint(p, request); _paint(p, request);
} }
@ -515,7 +521,7 @@ void PipPanel::updateOverState(QPoint point) {
setCursor([&] { setCursor([&] {
switch (_overState) { switch (_overState) {
case RectPart::Center: case RectPart::Center:
return style::cur_default; return style::cur_pointer;
case RectPart::TopLeft: case RectPart::TopLeft:
case RectPart::BottomRight: case RectPart::BottomRight:
return style::cur_sizefdiag; return style::cur_sizefdiag;
@ -655,6 +661,11 @@ void PipPanel::moveAnimated(QPoint to) {
} }
void PipPanel::updateDecorations() { void PipPanel::updateDecorations() {
const auto guard = gsl::finally([&] {
if (!_dragState) {
_saveGeometryRequests.fire({});
}
});
const auto position = countPosition(); const auto position = countPosition();
const auto center = position.geometry.center(); const auto center = position.geometry.center();
const auto use = Ui::Platform::TranslucentWindowsSupported(center); const auto use = Ui::Platform::TranslucentWindowsSupported(center);
@ -665,7 +676,7 @@ void PipPanel::updateDecorations() {
(position.attached & RectPart::Right) ? 0 : full.right(), (position.attached & RectPart::Right) ? 0 : full.right(),
(position.attached & RectPart::Bottom) ? 0 : full.bottom()); (position.attached & RectPart::Bottom) ? 0 : full.bottom());
_snapped = position.snapped; _snapped = position.snapped;
if (_padding == padding || _attached == position.attached) { if (_padding == padding && _attached == position.attached) {
return; return;
} }
const auto newGeometry = position.geometry.marginsAdded(padding); const auto newGeometry = position.geometry.marginsAdded(padding);
@ -675,9 +686,6 @@ void PipPanel::updateDecorations() {
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency); setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
setGeometry(newGeometry); setGeometry(newGeometry);
update(); update();
if (!_dragState) {
_saveGeometryRequests.fire({});
}
} }
Pip::Pip( Pip::Pip(
@ -690,18 +698,6 @@ Pip::Pip(
, _panel( , _panel(
_delegate->pipParentWidget(), _delegate->pipParentWidget(),
[=](QPainter &p, const FrameRequest &request) { paint(p, request); }) [=](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)) , _closeAndContinue(std::move(closeAndContinue))
, _destroy(std::move(destroy)) { , _destroy(std::move(destroy)) {
setupPanel(); setupPanel();
@ -725,39 +721,131 @@ void Pip::setupPanel() {
}, _panel.lifetime()); }, _panel.lifetime());
_panel.events( _panel.events(
) | rpl::filter([=](not_null<QEvent*> e) { ) | rpl::start_with_next([=](not_null<QEvent*> e) {
return e->type() == QEvent::Close; switch (e->type()) {
}) | rpl::start_with_next([=] { case QEvent::Close: handleClose(); break;
crl::on_main(&_panel, [=] { case QEvent::Leave: handleLeave(); break;
_destroy(); case QEvent::MouseMove:
}); handleMouseMove(static_cast<QMouseEvent*>(e.get())->pos());
break;
case QEvent::MouseButtonPress:
handleMousePress(static_cast<QMouseEvent*>(e.get())->button());
break;
case QEvent::MouseButtonRelease:
handleMouseRelease(static_cast<QMouseEvent*>(e.get())->button());
break;
}
}, _panel.lifetime()); }, _panel.lifetime());
} }
void Pip::setupButtons() { void Pip::handleClose() {
_panel.sizeValue( crl::on_main(&_panel, [=] {
) | rpl::start_with_next([=](QSize size) { _destroy();
_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());
_close->entity()->addClickHandler([=] { void Pip::handleLeave() {
_panel.close(); setOverState(OverState::None);
}); }
_pictureInPicture->entity()->addClickHandler([=] {
_closeAndContinue(); void Pip::handleMouseMove(QPoint position) {
}); setOverState(computeState(position));
_playPauseResume->entity()->addClickHandler([=] { }
playbackPauseResume();
}); void Pip::setOverState(OverState state) {
_close->show(anim::type::instant); if (_over == state) {
_pictureInPicture->show(anim::type::instant); return;
_playPauseResume->show(anim::type::instant); }
const auto was = _over;
_over = state;
const auto nowShown = (_over != OverState::None);
if ((was != OverState::None) != nowShown) {
_controlsShown.start(
[=] { _panel.update(); },
nowShown ? 0. : 1.,
nowShown ? 1. : 0.,
st::fadeWrapDuration,
anim::linear);
}
const auto check = [&](Button &button) {
const auto now = (_over == button.state);
if ((was == button.state) != now) {
button.active.start(
[=, &button] { _panel.update(button.icon); },
now ? 0. : 1.,
now ? 1. : 0.,
st::fadeWrapDuration,
anim::linear);
}
};
check(_close);
check(_enlarge);
check(_play);
_panel.update();
}
void Pip::handleMousePress(Qt::MouseButton button) {
if (button != Qt::LeftButton) {
return;
}
_pressed = _over;
}
void Pip::handleMouseRelease(Qt::MouseButton button) {
const auto pressed = base::take(_pressed);
if (button != Qt::LeftButton
|| _panel.dragging()
|| !pressed
|| *pressed != _over) {
return;
}
switch (_over) {
case OverState::Close: _panel.close(); break;
case OverState::Enlarge: _closeAndContinue(); break;
case OverState::Other: playbackPauseResume(); break;
}
}
void Pip::setupButtons() {
_close.state = OverState::Close;
_enlarge.state = OverState::Enlarge;
_playback.state = OverState::Playback;
_play.state = OverState::Other;
_panel.sizeValue(
) | rpl::map([=] {
return _panel.inner();
}) | rpl::start_with_next([=](QRect rect) {
const auto skip = st::pipControlSkip;
_close.area = QRect(
rect.x(),
rect.y(),
st::pipCloseIcon.width() + 2 * skip,
st::pipCloseIcon.height() + 2 * skip);
_close.icon = _close.area.marginsRemoved({ skip, skip, skip, skip });
_enlarge.area = _enlarge.icon = QRect(
rect.x() + rect.width() - 2 * skip - st::pipEnlargeIcon.width(),
rect.y(),
st::pipEnlargeIcon.width() + 2 * skip,
st::pipEnlargeIcon.height() + 2 * skip);
_enlarge.icon = _enlarge.area.marginsRemoved(
{ skip, skip, skip, skip });
_play.icon = QRect(
rect.x() + (rect.width() - st::pipPlayIcon.width()) / 2,
(rect.y()
+ rect.height()
- st::pipPlayBottom
- st::pipPlayIcon.height()),
st::pipPlayIcon.width(),
st::pipPlayIcon.height());
const auto playbackHeight = 2 * st::pipPlaybackSkip
+ st::pipPlaybackWidth;
_playback.area = QRect(
rect.x(),
rect.y() + rect.height() - playbackHeight,
rect.width(),
playbackHeight);
}, _panel.lifetime());
} }
void Pip::saveGeometry() { void Pip::saveGeometry() {
@ -768,9 +856,7 @@ void Pip::updatePlayPauseResumeState(const Player::TrackState &state) {
auto showPause = Player::ShowPauseIcon(state.state); auto showPause = Player::ShowPauseIcon(state.state);
if (showPause != _showPause) { if (showPause != _showPause) {
_showPause = showPause; _showPause = showPause;
_playPauseResume->entity()->setIconOverride( _panel.update();
_showPause ? &st::mediaviewPauseIcon : nullptr,
_showPause ? &st::mediaviewPauseIconOver : nullptr);
} }
} }
@ -788,10 +874,47 @@ void Pip::setupStreaming() {
void Pip::paint(QPainter &p, FrameRequest request) { void Pip::paint(QPainter &p, FrameRequest request) {
const auto image = videoFrameForDirectPaint(request); const auto image = videoFrameForDirectPaint(request);
p.drawImage(QRect{ QPoint(), request.outer / style::DevicePixelRatio() }, image); p.drawImage(
QRect{
_panel.inner().topLeft(),
request.outer / style::DevicePixelRatio() },
image);
if (_instance.player().ready()) { if (_instance.player().ready()) {
_instance.markFrameShown(); _instance.markFrameShown();
} }
paintControls(p);
}
void Pip::paintControls(QPainter &p) {
const auto shown = _controlsShown.value(
(_over != OverState::None) ? 1. : 0.);
if (!shown) {
return;
}
p.setOpacity(shown);
const auto outer = _panel.width();
const auto drawOne = [&](
const Button &button,
const style::icon &icon,
const style::icon &iconOver) {
const auto over = button.active.value(
(_over == button.state) ? 1. : 0.);
if (over < 1.) {
icon.paint(p, button.icon.x(), button.icon.y(), outer);
}
if (over > 0.) {
p.setOpacity(over * shown);
iconOver.paint(p, button.icon.x(), button.icon.y(), outer);
p.setOpacity(shown);
}
};
drawOne(
_play,
_showPause ? st::pipPauseIcon : st::pipPlayIcon,
_showPause ? st::pipPauseIconOver : st::pipPlayIconOver);
drawOne(_close, st::pipCloseIcon, st::pipCloseIconOver);
drawOne(_enlarge, st::pipEnlargeIcon, st::pipEnlargeIconOver);
} }
void Pip::handleStreamingUpdate(Streaming::Update &&update) { void Pip::handleStreamingUpdate(Streaming::Update &&update) {
@ -906,6 +1029,20 @@ QImage Pip::videoFrameForDirectPaint(const FrameRequest &request) const {
return result; return result;
} }
Pip::OverState Pip::computeState(QPoint position) const {
if (!_panel.inner().contains(position)) {
return OverState::None;
} else if (_close.area.contains(position)) {
return OverState::Close;
} else if (_enlarge.area.contains(position)) {
return OverState::Enlarge;
} else if (_playback.area.contains(position)) {
return OverState::Playback;
} else {
return OverState::Other;
}
}
void Pip::waitingAnimationCallback() { void Pip::waitingAnimationCallback() {
} }

View File

@ -53,6 +53,8 @@ public:
void setAspectRatio(QSize ratio); void setAspectRatio(QSize ratio);
[[nodiscard]] Position countPosition() const; [[nodiscard]] Position countPosition() const;
void setPosition(Position position); void setPosition(Position position);
[[nodiscard]] QRect inner() const;
[[nodiscard]] bool dragging() const;
[[nodiscard]] rpl::producer<> saveGeometryRequests() const; [[nodiscard]] rpl::producer<> saveGeometryRequests() const;
@ -113,6 +115,19 @@ public:
FnMut<void()> destroy); FnMut<void()> destroy);
private: private:
enum class OverState {
None,
Close,
Enlarge,
Playback,
Other,
};
struct Button {
QRect area;
QRect icon;
OverState state = OverState::None;
Ui::Animations::Simple active;
};
using FrameRequest = Streaming::FrameRequest; using FrameRequest = Streaming::FrameRequest;
void setupPanel(); void setupPanel();
@ -132,16 +147,30 @@ private:
[[nodiscard]] QImage videoFrame(const FrameRequest &request) const; [[nodiscard]] QImage videoFrame(const FrameRequest &request) const;
[[nodiscard]] QImage videoFrameForDirectPaint( [[nodiscard]] QImage videoFrameForDirectPaint(
const FrameRequest &request) const; const FrameRequest &request) const;
[[nodiscard]] OverState computeState(QPoint position) const;
void setOverState(OverState state);
void handleMouseMove(QPoint position);
void handleMousePress(Qt::MouseButton button);
void handleMouseRelease(Qt::MouseButton button);
void handleLeave();
void handleClose();
void paintControls(QPainter &p);
const not_null<Delegate*> _delegate; const not_null<Delegate*> _delegate;
Streaming::Instance _instance; Streaming::Instance _instance;
PipPanel _panel; PipPanel _panel;
QSize _size; 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; bool _showPause = false;
OverState _over = OverState::None;
std::optional<OverState> _pressed;
Button _close;
Button _enlarge;
Button _playback;
Button _play;
Ui::Animations::Simple _controlsShown;
FnMut<void()> _closeAndContinue; FnMut<void()> _closeAndContinue;
FnMut<void()> _destroy; FnMut<void()> _destroy;

View File

@ -31,10 +31,9 @@ PlaybackControls::PlaybackControls(
, _playbackProgress(std::make_unique<PlaybackProgress>()) , _playbackProgress(std::make_unique<PlaybackProgress>())
, _volumeToggle(this, st::mediaviewVolumeToggle) , _volumeToggle(this, st::mediaviewVolumeToggle)
, _volumeController(this, st::mediaviewPlayback) , _volumeController(this, st::mediaviewPlayback)
, _speedController(this, st::mediaviewPlayback) , _menuToggle(this, st::mediaviewMenuToggle)
, _speedLabel(this, st::mediaviewPlayProgressLabel)
, _fullScreenToggle(this, st::mediaviewFullScreenButton) , _fullScreenToggle(this, st::mediaviewFullScreenButton)
, _pictureInPicture(this, st::mediaviewFullScreenButton) , _pictureInPicture(this, st::mediaviewPipButton)
, _playedAlready(this, st::mediaviewPlayProgressLabel) , _playedAlready(this, st::mediaviewPlayProgressLabel)
, _toPlayLeft(this, st::mediaviewPlayProgressLabel) , _toPlayLeft(this, st::mediaviewPlayProgressLabel)
, _fadeAnimation(std::make_unique<Ui::FadeAnimation>(this)) { , _fadeAnimation(std::make_unique<Ui::FadeAnimation>(this)) {
@ -46,9 +45,6 @@ PlaybackControls::PlaybackControls(
fadeUpdated(opacity); fadeUpdated(opacity);
}); });
_pictureInPicture->setIconOverride(
&st::mediaviewFullScreenOutIcon,
&st::mediaviewFullScreenOutIconOver);
_pictureInPicture->addClickHandler([=] { _pictureInPicture->addClickHandler([=] {
_delegate->playbackControlsToPictureInPicture(); _delegate->playbackControlsToPictureInPicture();
}); });
@ -68,14 +64,6 @@ PlaybackControls::PlaybackControls(
updateVolumeToggleIcon(); updateVolumeToggleIcon();
}); });
_speedController->setPseudoDiscrete(
7,
[=](int index) { return (index + 2) / 4.; },
_delegate->playbackControlsCurrentSpeed(),
[=](float64 speed) { updatePlaybackSpeed(speed); });
updatePlaybackSpeed(_delegate->playbackControlsCurrentSpeed());
_speedController->setAlwaysDisplayMarker(false);
_playPauseResume->addClickHandler([=] { _playPauseResume->addClickHandler([=] {
if (_showPause) { if (_showPause) {
_delegate->playbackControlsPause(); _delegate->playbackControlsPause();
@ -142,7 +130,6 @@ void PlaybackControls::startFading(Callback start) {
showChildren(); showChildren();
_playbackSlider->disablePaint(true); _playbackSlider->disablePaint(true);
_volumeController->disablePaint(true); _volumeController->disablePaint(true);
_speedController->disablePaint(true);
_childrenHidden = false; _childrenHidden = false;
} }
start(); start();
@ -150,8 +137,7 @@ void PlaybackControls::startFading(Callback start) {
for (const auto child : children()) { for (const auto child : children()) {
if (child->isWidgetType() if (child->isWidgetType()
&& child != _playbackSlider && child != _playbackSlider
&& child != _volumeController && child != _volumeController) {
&& child != _speedController) {
static_cast<QWidget*>(child)->hide(); static_cast<QWidget*>(child)->hide();
} }
} }
@ -161,7 +147,6 @@ void PlaybackControls::startFading(Callback start) {
} }
_playbackSlider->disablePaint(false); _playbackSlider->disablePaint(false);
_volumeController->disablePaint(false); _volumeController->disablePaint(false);
_speedController->disablePaint(false);
} }
void PlaybackControls::showAnimated() { void PlaybackControls::showAnimated() {
@ -183,14 +168,10 @@ void PlaybackControls::fadeFinished() {
void PlaybackControls::fadeUpdated(float64 opacity) { void PlaybackControls::fadeUpdated(float64 opacity) {
_playbackSlider->setFadeOpacity(opacity); _playbackSlider->setFadeOpacity(opacity);
_volumeController->setFadeOpacity(opacity); _volumeController->setFadeOpacity(opacity);
_speedController->setFadeOpacity(opacity);
} }
void PlaybackControls::updatePlaybackSpeed(float64 speed) { void PlaybackControls::updatePlaybackSpeed(float64 speed) {
_delegate->playbackControlsSpeedChanged(speed); _delegate->playbackControlsSpeedChanged(speed);
//const auto percent = int(std::round(speed * 100.));
//_speedLabel->setText(QString::number(percent) + '%');
_speedLabel->setText(QString::number(speed) + 'x');
resizeEvent(nullptr); resizeEvent(nullptr);
} }
@ -205,19 +186,15 @@ void PlaybackControls::updateVolumeToggleIcon() {
_volumeToggle->setIconOverride([&] { _volumeToggle->setIconOverride([&] {
return (volume <= 0.) return (volume <= 0.)
? nullptr ? nullptr
: (volume < 1 / 3.) : (volume < 1 / 2.)
? &st::mediaviewVolumeIcon1 ? &st::mediaviewVolumeIcon1
: (volume < 2 / 3.) : &st::mediaviewVolumeIcon2;
? &st::mediaviewVolumeIcon2
: &st::mediaviewVolumeIcon3;
}(), [&] { }(), [&] {
return (volume <= 0.) return (volume <= 0.)
? nullptr ? nullptr
: (volume < 1 / 3.) : (volume < 1 / 2.)
? &st::mediaviewVolumeIcon1Over ? &st::mediaviewVolumeIcon1Over
: (volume < 2 / 3.) : &st::mediaviewVolumeIcon2Over;
? &st::mediaviewVolumeIcon2Over
: &st::mediaviewVolumeIcon3Over;
}()); }());
} }
@ -249,14 +226,8 @@ void PlaybackControls::setLoadingProgress(int ready, int total) {
const auto percent = int(std::round(progress * 100)); const auto percent = int(std::round(progress * 100));
if (_loadingPercent != percent) { if (_loadingPercent != percent) {
_loadingPercent = percent; _loadingPercent = percent;
_downloadProgress->setText(tr::lng_mediaview_video_loading( _downloadProgress->setText(QString::number(percent) + '%');
tr::now, updateDownloadProgressPosition();
lt_percent,
QString::number(percent) + '%'));
if (_playbackSlider->width() > _downloadProgress->width()) {
const auto left = (_playbackSlider->width() - _downloadProgress->width()) / 2;
_downloadProgress->move(_playbackSlider->x() + left, st::mediaviewPlayProgressTop);
}
refreshFadeCache(); refreshFadeCache();
} }
} else { } else {
@ -337,44 +308,48 @@ void PlaybackControls::setInFullScreen(bool inFullScreen) {
} }
void PlaybackControls::resizeEvent(QResizeEvent *e) { void PlaybackControls::resizeEvent(QResizeEvent *e) {
const auto skip = st::mediaviewFullScreenLeft; const auto textSkip = st::mediaviewPlayProgressSkip;
const auto textLeft = st::mediaviewPlayProgressLeft;
auto playbackWidth = width() - 2 * skip; const auto textTop = st::mediaviewPlaybackTop + (_playbackSlider->height() - _playedAlready->height()) / 2;
_playedAlready->moveToLeft(textLeft + textSkip, textTop);
_toPlayLeft->moveToRight(textLeft + textSkip, textTop);
const auto remove = 2 * textLeft + 4 * textSkip + _playedAlready->width() + _toPlayLeft->width();
auto playbackWidth = width() - remove;
_playbackSlider->resize(playbackWidth, st::mediaviewPlayback.seekSize.height()); _playbackSlider->resize(playbackWidth, st::mediaviewPlayback.seekSize.height());
_playbackSlider->moveToLeft(st::mediaviewPlayPauseLeft, st::mediaviewPlaybackTop); _playbackSlider->moveToLeft(textLeft + 2 * textSkip + _playedAlready->width(), st::mediaviewPlaybackTop);
_playedAlready->moveToLeft(st::mediaviewPlayPauseLeft, st::mediaviewPlayProgressTop); _playPauseResume->moveToLeft(
_toPlayLeft->moveToRight(st::mediaviewPlayPauseLeft, st::mediaviewPlayProgressTop); (width() - _playPauseResume->width()) / 2,
if (_downloadProgress) { st::mediaviewPlayButtonTop);
const auto left = (_playbackSlider->width() - _downloadProgress->width()) / 2;
_downloadProgress->move(_playbackSlider->x() + left, st::mediaviewPlayProgressTop); auto right = st::mediaviewMenuToggleSkip;
_menuToggle->moveToRight(right, st::mediaviewButtonsTop);
right += _menuToggle->width() + st::mediaviewPipButtonSkip;
_pictureInPicture->moveToRight(right, st::mediaviewButtonsTop);
right += _pictureInPicture->width() + st::mediaviewFullScreenButtonSkip;
_fullScreenToggle->moveToRight(right, st::mediaviewButtonsTop);
updateDownloadProgressPosition();
auto left = st::mediaviewVolumeToggleSkip;
_volumeToggle->moveToLeft(left, st::mediaviewVolumeTop);
left += _volumeToggle->width() + st::mediaviewVolumeSkip;
_volumeController->resize(
st::mediaviewVolumeWidth,
st::mediaviewPlayback.seekSize.height());
_volumeController->moveToLeft(left, st::mediaviewVolumeTop + (_volumeToggle->height() - _volumeController->height()) / 2);
}
void PlaybackControls::updateDownloadProgressPosition() {
if (!_downloadProgress) {
return;
} }
const auto left = _playPauseResume->x() + _playPauseResume->width();
auto left = skip; const auto right = _fullScreenToggle->x();
const auto playTop = height() - _playPauseResume->height() - skip; const auto available = right - left;
_playPauseResume->moveToLeft(left, playTop); const auto x = left + (available - _downloadProgress->width()) / 2;
left += _playPauseResume->width() + skip; const auto y = _playPauseResume->y() + (_playPauseResume->height() - _downloadProgress->height()) / 2;
_downloadProgress->move(x, y);
_fullScreenToggle->moveToLeft(left, playTop);
left += _fullScreenToggle->width() + skip;
_pictureInPicture->moveToLeft(left, playTop);
auto right = skip;
const auto volumeTop = playTop + (_fullScreenToggle->height() - _volumeController->height()) / 2;
const auto volumeIconTop = playTop + (_fullScreenToggle->height() - _volumeToggle->height()) / 2;
_volumeController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
_volumeController->moveToRight(right, volumeTop);
right += _volumeController->width();
_volumeToggle->moveToRight(right, volumeIconTop);
right += _volumeToggle->width() + 2 * skip;
const auto speedTop = volumeTop;
const auto speedLabelTop = playTop + (_fullScreenToggle->height() - _speedLabel->height()) / 2;
_speedController->resize(st::mediaviewVolumeWidth, st::mediaviewPlayback.seekSize.height());
_speedController->moveToRight(right, volumeTop);
right += _speedController->width() + st::semiboldFont->spacew * 3;
_speedLabel->moveToRight(right, speedLabelTop);
} }
void PlaybackControls::paintEvent(QPaintEvent *e) { void PlaybackControls::paintEvent(QPaintEvent *e) {
@ -387,7 +362,6 @@ void PlaybackControls::paintEvent(QPaintEvent *e) {
showChildren(); showChildren();
_playbackSlider->setFadeOpacity(1.); _playbackSlider->setFadeOpacity(1.);
_volumeController->setFadeOpacity(1.); _volumeController->setFadeOpacity(1.);
_speedController->setFadeOpacity(1.);
_childrenHidden = false; _childrenHidden = false;
} }
App::roundRect(p, rect(), st::mediaviewSaveMsgBg, MediaviewSaveCorners); App::roundRect(p, rect(), st::mediaviewSaveMsgBg, MediaviewSaveCorners);

View File

@ -75,6 +75,7 @@ private:
void updatePlaybackSpeed(float64 speed); void updatePlaybackSpeed(float64 speed);
void updateVolumeToggleIcon(); void updateVolumeToggleIcon();
void updateDownloadProgressPosition();
void updatePlayPauseResumeState(const Player::TrackState &state); void updatePlayPauseResumeState(const Player::TrackState &state);
void updateTimeTexts(const Player::TrackState &state); void updateTimeTexts(const Player::TrackState &state);
@ -98,8 +99,7 @@ private:
std::unique_ptr<PlaybackProgress> _receivedTillProgress; std::unique_ptr<PlaybackProgress> _receivedTillProgress;
object_ptr<Ui::IconButton> _volumeToggle; object_ptr<Ui::IconButton> _volumeToggle;
object_ptr<Ui::MediaSlider> _volumeController; object_ptr<Ui::MediaSlider> _volumeController;
object_ptr<Ui::MediaSlider> _speedController; object_ptr<Ui::IconButton> _menuToggle;
object_ptr<Ui::LabelSimple> _speedLabel;
object_ptr<Ui::IconButton> _fullScreenToggle; object_ptr<Ui::IconButton> _fullScreenToggle;
object_ptr<Ui::IconButton> _pictureInPicture; object_ptr<Ui::IconButton> _pictureInPicture;
object_ptr<Ui::LabelSimple> _playedAlready; object_ptr<Ui::LabelSimple> _playedAlready;

View File

@ -20,61 +20,85 @@ mediaviewPlayback: MediaSlider {
activeFgDisabled: mediaviewPlaybackActive; activeFgDisabled: mediaviewPlaybackActive;
inactiveFgDisabled: mediaviewPlaybackInactive; inactiveFgDisabled: mediaviewPlaybackInactive;
receivedTillFg: mediaviewPlaybackInactiveOver; receivedTillFg: mediaviewPlaybackInactiveOver;
seekSize: size(11px, 11px); seekSize: size(12px, 12px);
duration: mediaviewOverDuration;
}
mediaviewPlaybackTop: 52px;
mediaviewControlsButton: IconButton {
ripple: RippleAnimation(defaultRippleAnimation) {
color: mediaviewPlaybackIconRipple;
}
rippleAreaPosition: point(0px, 0px);
duration: mediaviewOverDuration; duration: mediaviewOverDuration;
} }
mediaviewControllerSize: size(480px, 100px); mediaviewControllerSize: size(481px, 75px);
mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) { mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) {
font: semiboldFont; font: semiboldFont;
textFg: mediaviewPlaybackProgressFg; textFg: mediaviewPlaybackProgressFg;
} }
mediaviewPlayProgressTop: 11px; mediaviewPlayProgressSkip: 8px;
mediaviewPlayButton: IconButton { mediaviewPlayProgressLeft: 8px;
width: 25px; mediaviewPlayButtonTop: 5px;
height: 24px; mediaviewPlayButton: IconButton(mediaviewControlsButton) {
width: 42px;
height: 42px;
rippleAreaSize: 42px;
icon: icon {{ "media_play", mediaviewPlaybackIconFg, point(3px, 0px) }}; icon: icon {{ "player_play", mediaviewPlaybackIconFg }};
iconOver: icon {{ "media_play", mediaviewPlaybackIconFgOver, point(3px, 0px) }}; iconOver: icon {{ "player_play", mediaviewPlaybackIconFgOver }};
iconPosition: point(3px, 1px); iconPosition: point(9px, 9px);
duration: mediaviewOverDuration;
} }
mediaviewPauseIcon: icon {{ "media_pause", mediaviewPlaybackIconFg, point(1px, 1px) }}; mediaviewPauseIcon: icon {{ "player_pause", mediaviewPlaybackIconFg }};
mediaviewPauseIconOver: icon {{ "media_pause", mediaviewPlaybackIconFgOver, point(1px, 1px) }}; mediaviewPauseIconOver: icon {{ "player_pause", mediaviewPlaybackIconFgOver }};
mediaviewPlayPauseLeft: 17px;
mediaviewFullScreenLeft: 17px;
mediaviewVolumeLeft: 7px;
mediaviewFullScreenButton: IconButton(mediaviewPlayButton) { mediaviewButtonsTop: 7px;
icon: icon {{ "media_fullscreen_to", mediaviewPlaybackIconFg, point(0px, 0px) }};
iconOver: icon {{ "media_fullscreen_to", mediaviewPlaybackIconFgOver, point(0px, 0px) }}; mediaviewMenuToggleSkip: 4px;
iconPosition: point(0px, 1px); mediaviewMenuToggle: IconButton(mediaviewControlsButton) {
width: 34px;
height: 34px;
rippleAreaSize: 34px;
icon: icon {{ "player_more", mediaviewPlaybackIconFg }};
iconOver: icon {{ "player_more", mediaviewPlaybackIconFgOver }};
iconPosition: point(5px, 5px);
} }
mediaviewFullScreenOutIcon: icon {{ "media_fullscreen_from", mediaviewPlaybackIconFg, point(0px, 0px) }};
mediaviewFullScreenOutIconOver: icon {{ "media_fullscreen_from", mediaviewPlaybackIconFgOver, point(0px, 0px) }};
mediaviewPlaybackTop: 28px; mediaviewPipButtonSkip: 5px;
mediaviewPipButton: IconButton(mediaviewMenuToggle) {
icon: icon {{ "player_pip", mediaviewPlaybackIconFg }};
iconOver: icon {{ "player_pip", mediaviewPlaybackIconFgOver }};
}
mediaviewVolumeWidth: 60px; mediaviewFullScreenButtonSkip: 8px;
mediaviewControllerRadius: roundRadiusLarge; mediaviewFullScreenButton: IconButton(mediaviewMenuToggle) {
icon: icon {{ "player_fullscreen", mediaviewPlaybackIconFg }};
iconOver: icon {{ "player_fullscreen", mediaviewPlaybackIconFgOver }};
}
mediaviewFullScreenOutIcon: icon {{ "player_minimize", mediaviewPlaybackIconFg }};
mediaviewFullScreenOutIconOver: icon {{ "player_minimize", mediaviewPlaybackIconFgOver }};
mediaviewVolumeIcon0: icon {{ "player_volume0", mediaviewPlaybackIconFg }}; mediaviewVolumeWidth: 75px;
mediaviewVolumeIcon0Over: icon {{ "player_volume0", mediaviewPlaybackIconFgOver }}; mediaviewControllerRadius: 9px;
mediaviewVolumeIcon1: icon {{ "player_volume1", mediaviewPlaybackIconFg }};
mediaviewVolumeIcon1Over: icon {{ "player_volume1", mediaviewPlaybackIconFgOver }};
mediaviewVolumeIcon2: icon {{ "player_volume2", mediaviewPlaybackIconFg }};
mediaviewVolumeIcon2Over: icon {{ "player_volume2", mediaviewPlaybackIconFgOver }};
mediaviewVolumeIcon3: icon {{ "player_volume3", mediaviewPlaybackIconFg }};
mediaviewVolumeIcon3Over: icon {{ "player_volume3", mediaviewPlaybackIconFgOver }};
mediaviewVolumeToggle: IconButton {
width: 31px;
height: 29px;
mediaviewVolumeIcon0: icon {{ "player_volume_off", mediaviewPlaybackIconFg }};
mediaviewVolumeIcon0Over: icon {{ "player_volume_off", mediaviewPlaybackIconFgOver }};
mediaviewVolumeIcon1: icon {{ "player_volume_small", mediaviewPlaybackIconFg }};
mediaviewVolumeIcon1Over: icon {{ "player_volume_small", mediaviewPlaybackIconFgOver }};
mediaviewVolumeIcon2: icon {{ "player_volume_on", mediaviewPlaybackIconFg }};
mediaviewVolumeIcon2Over: icon {{ "player_volume_on", mediaviewPlaybackIconFgOver }};
mediaviewVolumeTop: 10px;
mediaviewVolumeToggleSkip: 11px;
mediaviewVolumeToggle: IconButton(mediaviewControlsButton) {
width: 30px;
height: 30px;
rippleAreaSize: 30px;
icon: mediaviewVolumeIcon0; icon: mediaviewVolumeIcon0;
iconOver: mediaviewVolumeIcon0Over; iconOver: mediaviewVolumeIcon0Over;
iconPosition: point(8px, 8px); iconPosition: point(3px, 3px);
} }
mediaviewVolumeSkip: 4px;
mediaviewLeft: icon {{ "mediaview_next-flip_horizontal", mediaviewControlFg }}; mediaviewLeft: icon {{ "mediaview_next-flip_horizontal", mediaviewControlFg }};
mediaviewRight: icon {{ "mediaview_next", mediaviewControlFg }}; mediaviewRight: icon {{ "mediaview_next", mediaviewControlFg }};
@ -229,4 +253,16 @@ pipDefaultSize: 320px;
pipMinimalSize: 100px; pipMinimalSize: 100px;
pipBorderSkip: 20px; pipBorderSkip: 20px;
pipBorderSnapArea: 16px; pipBorderSnapArea: 16px;
pipResizeArea: 10px; pipResizeArea: 10px;
pipControlSkip: 6px;
pipPlaybackWidth: 2px;
pipPlaybackSkip: 4px;
pipPlayBottom: 16px;
pipPlayIcon: icon {{ "player_pip_play", mediaviewPipControlsFg }};
pipPlayIconOver: icon {{ "player_pip_play", mediaviewPipControlsFgOver }};
pipPauseIcon: icon {{ "player_pip_pause", mediaviewPipControlsFg }};
pipPauseIconOver: icon {{ "player_pip_pause", mediaviewPipControlsFgOver }};
pipCloseIcon: icon {{ "player_pip_close", mediaviewPlaybackIconFg }};
pipCloseIconOver: icon {{ "player_pip_close", mediaviewPlaybackIconFgOver }};
pipEnlargeIcon: icon {{ "player_pip_enlarge", mediaviewPlaybackIconFg }};
pipEnlargeIconOver: icon {{ "player_pip_enlarge", mediaviewPlaybackIconFgOver }};