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().finished())) {
startStreamingPlayer();
} else {
updatePlaybackState();
}
return true;
}

View File

@ -20,7 +20,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "window/window_controller.h"
#include "styles/style_window.h"
#include "styles/style_mediaview.h"
#include "styles/style_layers.h" // st::boxTitleClose
#include "styles/style_calls.h" // st::callShadow
#include <QtGui/QWindow>
@ -292,6 +291,14 @@ void PipPanel::setPosition(Position position) {
setPositionDefault();
}
QRect PipPanel::inner() const {
return rect().marginsRemoved(_padding);
}
bool PipPanel::dragging() const {
return _dragState.has_value();
}
rpl::producer<> PipPanel::saveGeometryRequests() const {
return _saveGeometryRequests.events();
}
@ -433,7 +440,7 @@ void PipPanel::paintEvent(QPaintEvent *e) {
}
auto request = FrameRequest();
const auto inner = rect().marginsRemoved(_padding);
const auto inner = this->inner();
request.resize = request.outer = inner.size() * style::DevicePixelRatio();
request.corners = RectPart(0)
| ((_attached & (RectPart::Left | RectPart::Top))
@ -453,7 +460,6 @@ void PipPanel::paintEvent(QPaintEvent *e) {
const auto sides = RectPart::AllSides & ~_attached;
Ui::Shadow::paint(p, inner, width(), st::callShadow);
}
p.translate(_padding.left(), _padding.top());
_paint(p, request);
}
@ -515,7 +521,7 @@ void PipPanel::updateOverState(QPoint point) {
setCursor([&] {
switch (_overState) {
case RectPart::Center:
return style::cur_default;
return style::cur_pointer;
case RectPart::TopLeft:
case RectPart::BottomRight:
return style::cur_sizefdiag;
@ -655,6 +661,11 @@ void PipPanel::moveAnimated(QPoint to) {
}
void PipPanel::updateDecorations() {
const auto guard = gsl::finally([&] {
if (!_dragState) {
_saveGeometryRequests.fire({});
}
});
const auto position = countPosition();
const auto center = position.geometry.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::Bottom) ? 0 : full.bottom());
_snapped = position.snapped;
if (_padding == padding || _attached == position.attached) {
if (_padding == padding && _attached == position.attached) {
return;
}
const auto newGeometry = position.geometry.marginsAdded(padding);
@ -675,9 +686,6 @@ void PipPanel::updateDecorations() {
setAttribute(Qt::WA_OpaquePaintEvent, !_useTransparency);
setGeometry(newGeometry);
update();
if (!_dragState) {
_saveGeometryRequests.fire({});
}
}
Pip::Pip(
@ -690,18 +698,6 @@ Pip::Pip(
, _panel(
_delegate->pipParentWidget(),
[=](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)) {
setupPanel();
@ -725,39 +721,131 @@ void Pip::setupPanel() {
}, _panel.lifetime());
_panel.events(
) | rpl::filter([=](not_null<QEvent*> e) {
return e->type() == QEvent::Close;
}) | rpl::start_with_next([=] {
crl::on_main(&_panel, [=] {
_destroy();
});
) | rpl::start_with_next([=](not_null<QEvent*> e) {
switch (e->type()) {
case QEvent::Close: handleClose(); break;
case QEvent::Leave: handleLeave(); break;
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());
}
void Pip::setupButtons() {
_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());
void Pip::handleClose() {
crl::on_main(&_panel, [=] {
_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);
void Pip::handleLeave() {
setOverState(OverState::None);
}
void Pip::handleMouseMove(QPoint position) {
setOverState(computeState(position));
}
void Pip::setOverState(OverState state) {
if (_over == state) {
return;
}
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() {
@ -768,9 +856,7 @@ 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);
_panel.update();
}
}
@ -788,10 +874,47 @@ void Pip::setupStreaming() {
void Pip::paint(QPainter &p, FrameRequest 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()) {
_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) {
@ -906,6 +1029,20 @@ QImage Pip::videoFrameForDirectPaint(const FrameRequest &request) const {
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() {
}

View File

@ -53,6 +53,8 @@ public:
void setAspectRatio(QSize ratio);
[[nodiscard]] Position countPosition() const;
void setPosition(Position position);
[[nodiscard]] QRect inner() const;
[[nodiscard]] bool dragging() const;
[[nodiscard]] rpl::producer<> saveGeometryRequests() const;
@ -113,6 +115,19 @@ public:
FnMut<void()> destroy);
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;
void setupPanel();
@ -132,16 +147,30 @@ private:
[[nodiscard]] QImage videoFrame(const FrameRequest &request) const;
[[nodiscard]] QImage videoFrameForDirectPaint(
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;
Streaming::Instance _instance;
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;
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()> _destroy;

View File

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

View File

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

View File

@ -20,61 +20,85 @@ mediaviewPlayback: MediaSlider {
activeFgDisabled: mediaviewPlaybackActive;
inactiveFgDisabled: mediaviewPlaybackInactive;
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;
}
mediaviewControllerSize: size(480px, 100px);
mediaviewControllerSize: size(481px, 75px);
mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) {
font: semiboldFont;
textFg: mediaviewPlaybackProgressFg;
}
mediaviewPlayProgressTop: 11px;
mediaviewPlayButton: IconButton {
width: 25px;
height: 24px;
mediaviewPlayProgressSkip: 8px;
mediaviewPlayProgressLeft: 8px;
mediaviewPlayButtonTop: 5px;
mediaviewPlayButton: IconButton(mediaviewControlsButton) {
width: 42px;
height: 42px;
rippleAreaSize: 42px;
icon: icon {{ "media_play", mediaviewPlaybackIconFg, point(3px, 0px) }};
iconOver: icon {{ "media_play", mediaviewPlaybackIconFgOver, point(3px, 0px) }};
iconPosition: point(3px, 1px);
duration: mediaviewOverDuration;
icon: icon {{ "player_play", mediaviewPlaybackIconFg }};
iconOver: icon {{ "player_play", mediaviewPlaybackIconFgOver }};
iconPosition: point(9px, 9px);
}
mediaviewPauseIcon: icon {{ "media_pause", mediaviewPlaybackIconFg, point(1px, 1px) }};
mediaviewPauseIconOver: icon {{ "media_pause", mediaviewPlaybackIconFgOver, point(1px, 1px) }};
mediaviewPlayPauseLeft: 17px;
mediaviewFullScreenLeft: 17px;
mediaviewVolumeLeft: 7px;
mediaviewPauseIcon: icon {{ "player_pause", mediaviewPlaybackIconFg }};
mediaviewPauseIconOver: icon {{ "player_pause", mediaviewPlaybackIconFgOver }};
mediaviewFullScreenButton: IconButton(mediaviewPlayButton) {
icon: icon {{ "media_fullscreen_to", mediaviewPlaybackIconFg, point(0px, 0px) }};
iconOver: icon {{ "media_fullscreen_to", mediaviewPlaybackIconFgOver, point(0px, 0px) }};
iconPosition: point(0px, 1px);
mediaviewButtonsTop: 7px;
mediaviewMenuToggleSkip: 4px;
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;
mediaviewControllerRadius: roundRadiusLarge;
mediaviewFullScreenButtonSkip: 8px;
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 }};
mediaviewVolumeIcon0Over: icon {{ "player_volume0", mediaviewPlaybackIconFgOver }};
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;
mediaviewVolumeWidth: 75px;
mediaviewControllerRadius: 9px;
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;
iconOver: mediaviewVolumeIcon0Over;
iconPosition: point(8px, 8px);
iconPosition: point(3px, 3px);
}
mediaviewVolumeSkip: 4px;
mediaviewLeft: icon {{ "mediaview_next-flip_horizontal", mediaviewControlFg }};
mediaviewRight: icon {{ "mediaview_next", mediaviewControlFg }};
@ -229,4 +253,16 @@ pipDefaultSize: 320px;
pipMinimalSize: 100px;
pipBorderSkip: 20px;
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 }};