diff --git a/Telegram/Resources/icons/player_check.png b/Telegram/Resources/icons/player_check.png new file mode 100644 index 000000000..cdba65b47 Binary files /dev/null and b/Telegram/Resources/icons/player_check.png differ diff --git a/Telegram/Resources/icons/player_check@2x.png b/Telegram/Resources/icons/player_check@2x.png new file mode 100644 index 000000000..9d432032b Binary files /dev/null and b/Telegram/Resources/icons/player_check@2x.png differ diff --git a/Telegram/Resources/icons/player_check@3x.png b/Telegram/Resources/icons/player_check@3x.png new file mode 100644 index 000000000..097ad06c5 Binary files /dev/null and b/Telegram/Resources/icons/player_check@3x.png differ diff --git a/Telegram/Resources/icons/player_fullscreen.png b/Telegram/Resources/icons/player_fullscreen.png new file mode 100644 index 000000000..bb3bbd363 Binary files /dev/null and b/Telegram/Resources/icons/player_fullscreen.png differ diff --git a/Telegram/Resources/icons/player_fullscreen@2x.png b/Telegram/Resources/icons/player_fullscreen@2x.png new file mode 100644 index 000000000..79abf0a88 Binary files /dev/null and b/Telegram/Resources/icons/player_fullscreen@2x.png differ diff --git a/Telegram/Resources/icons/player_fullscreen@3x.png b/Telegram/Resources/icons/player_fullscreen@3x.png new file mode 100644 index 000000000..9354611f5 Binary files /dev/null and b/Telegram/Resources/icons/player_fullscreen@3x.png differ diff --git a/Telegram/Resources/icons/player_minimize.png b/Telegram/Resources/icons/player_minimize.png new file mode 100644 index 000000000..a4d648eb7 Binary files /dev/null and b/Telegram/Resources/icons/player_minimize.png differ diff --git a/Telegram/Resources/icons/player_minimize@2x.png b/Telegram/Resources/icons/player_minimize@2x.png new file mode 100644 index 000000000..efbd5b0c9 Binary files /dev/null and b/Telegram/Resources/icons/player_minimize@2x.png differ diff --git a/Telegram/Resources/icons/player_minimize@3x.png b/Telegram/Resources/icons/player_minimize@3x.png new file mode 100644 index 000000000..16367d5d6 Binary files /dev/null and b/Telegram/Resources/icons/player_minimize@3x.png differ diff --git a/Telegram/Resources/icons/player_more.png b/Telegram/Resources/icons/player_more.png new file mode 100644 index 000000000..b61a629d8 Binary files /dev/null and b/Telegram/Resources/icons/player_more.png differ diff --git a/Telegram/Resources/icons/player_more@2x.png b/Telegram/Resources/icons/player_more@2x.png new file mode 100644 index 000000000..0fd9fdab2 Binary files /dev/null and b/Telegram/Resources/icons/player_more@2x.png differ diff --git a/Telegram/Resources/icons/player_more@3x.png b/Telegram/Resources/icons/player_more@3x.png new file mode 100644 index 000000000..0ca0520d6 Binary files /dev/null and b/Telegram/Resources/icons/player_more@3x.png differ diff --git a/Telegram/Resources/icons/player_pause.png b/Telegram/Resources/icons/player_pause.png new file mode 100644 index 000000000..a09d1730a Binary files /dev/null and b/Telegram/Resources/icons/player_pause.png differ diff --git a/Telegram/Resources/icons/player_pause@2x.png b/Telegram/Resources/icons/player_pause@2x.png new file mode 100644 index 000000000..ef66eea10 Binary files /dev/null and b/Telegram/Resources/icons/player_pause@2x.png differ diff --git a/Telegram/Resources/icons/player_pause@3x.png b/Telegram/Resources/icons/player_pause@3x.png new file mode 100644 index 000000000..5392c68d8 Binary files /dev/null and b/Telegram/Resources/icons/player_pause@3x.png differ diff --git a/Telegram/Resources/icons/player_pip.png b/Telegram/Resources/icons/player_pip.png new file mode 100644 index 000000000..52e167ba1 Binary files /dev/null and b/Telegram/Resources/icons/player_pip.png differ diff --git a/Telegram/Resources/icons/player_pip@2x.png b/Telegram/Resources/icons/player_pip@2x.png new file mode 100644 index 000000000..bfa8e10f7 Binary files /dev/null and b/Telegram/Resources/icons/player_pip@2x.png differ diff --git a/Telegram/Resources/icons/player_pip@3x.png b/Telegram/Resources/icons/player_pip@3x.png new file mode 100644 index 000000000..cf0cd7990 Binary files /dev/null and b/Telegram/Resources/icons/player_pip@3x.png differ diff --git a/Telegram/Resources/icons/player_pip_close.png b/Telegram/Resources/icons/player_pip_close.png new file mode 100644 index 000000000..72126ed98 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_close.png differ diff --git a/Telegram/Resources/icons/player_pip_close@2x.png b/Telegram/Resources/icons/player_pip_close@2x.png new file mode 100644 index 000000000..56dfd6f56 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_close@2x.png differ diff --git a/Telegram/Resources/icons/player_pip_close@3x.png b/Telegram/Resources/icons/player_pip_close@3x.png new file mode 100644 index 000000000..47bef1461 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_close@3x.png differ diff --git a/Telegram/Resources/icons/player_pip_enlarge.png b/Telegram/Resources/icons/player_pip_enlarge.png new file mode 100644 index 000000000..d9c156a4d Binary files /dev/null and b/Telegram/Resources/icons/player_pip_enlarge.png differ diff --git a/Telegram/Resources/icons/player_pip_enlarge@2x.png b/Telegram/Resources/icons/player_pip_enlarge@2x.png new file mode 100644 index 000000000..1bfb76b69 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_enlarge@2x.png differ diff --git a/Telegram/Resources/icons/player_pip_enlarge@3x.png b/Telegram/Resources/icons/player_pip_enlarge@3x.png new file mode 100644 index 000000000..8961ce7b0 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_enlarge@3x.png differ diff --git a/Telegram/Resources/icons/player_pip_pause.png b/Telegram/Resources/icons/player_pip_pause.png new file mode 100644 index 000000000..83c8ac0b1 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_pause.png differ diff --git a/Telegram/Resources/icons/player_pip_pause@2x.png b/Telegram/Resources/icons/player_pip_pause@2x.png new file mode 100644 index 000000000..155f116e7 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_pause@2x.png differ diff --git a/Telegram/Resources/icons/player_pip_pause@3x.png b/Telegram/Resources/icons/player_pip_pause@3x.png new file mode 100644 index 000000000..c72ade429 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_pause@3x.png differ diff --git a/Telegram/Resources/icons/player_pip_play.png b/Telegram/Resources/icons/player_pip_play.png new file mode 100644 index 000000000..b7b0c8620 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_play.png differ diff --git a/Telegram/Resources/icons/player_pip_play@2x.png b/Telegram/Resources/icons/player_pip_play@2x.png new file mode 100644 index 000000000..77c3a6f13 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_play@2x.png differ diff --git a/Telegram/Resources/icons/player_pip_play@3x.png b/Telegram/Resources/icons/player_pip_play@3x.png new file mode 100644 index 000000000..cc5662de7 Binary files /dev/null and b/Telegram/Resources/icons/player_pip_play@3x.png differ diff --git a/Telegram/Resources/icons/player_play.png b/Telegram/Resources/icons/player_play.png new file mode 100644 index 000000000..4dc3dab18 Binary files /dev/null and b/Telegram/Resources/icons/player_play.png differ diff --git a/Telegram/Resources/icons/player_play@2x.png b/Telegram/Resources/icons/player_play@2x.png new file mode 100644 index 000000000..e4a2e5186 Binary files /dev/null and b/Telegram/Resources/icons/player_play@2x.png differ diff --git a/Telegram/Resources/icons/player_play@3x.png b/Telegram/Resources/icons/player_play@3x.png new file mode 100644 index 000000000..8a14c8cea Binary files /dev/null and b/Telegram/Resources/icons/player_play@3x.png differ diff --git a/Telegram/Resources/icons/player_volume_off.png b/Telegram/Resources/icons/player_volume_off.png new file mode 100644 index 000000000..88ed4e391 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_off.png differ diff --git a/Telegram/Resources/icons/player_volume_off@2x.png b/Telegram/Resources/icons/player_volume_off@2x.png new file mode 100644 index 000000000..c4df75d9c Binary files /dev/null and b/Telegram/Resources/icons/player_volume_off@2x.png differ diff --git a/Telegram/Resources/icons/player_volume_off@3x.png b/Telegram/Resources/icons/player_volume_off@3x.png new file mode 100644 index 000000000..b31bad377 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_off@3x.png differ diff --git a/Telegram/Resources/icons/player_volume_on.png b/Telegram/Resources/icons/player_volume_on.png new file mode 100644 index 000000000..eaddd3674 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_on.png differ diff --git a/Telegram/Resources/icons/player_volume_on@2x.png b/Telegram/Resources/icons/player_volume_on@2x.png new file mode 100644 index 000000000..f931fe241 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_on@2x.png differ diff --git a/Telegram/Resources/icons/player_volume_on@3x.png b/Telegram/Resources/icons/player_volume_on@3x.png new file mode 100644 index 000000000..5d10c66a6 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_on@3x.png differ diff --git a/Telegram/Resources/icons/player_volume_small.png b/Telegram/Resources/icons/player_volume_small.png new file mode 100644 index 000000000..8cbcaf5c4 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_small.png differ diff --git a/Telegram/Resources/icons/player_volume_small@2x.png b/Telegram/Resources/icons/player_volume_small@2x.png new file mode 100644 index 000000000..3098bed94 Binary files /dev/null and b/Telegram/Resources/icons/player_volume_small@2x.png differ diff --git a/Telegram/Resources/icons/player_volume_small@3x.png b/Telegram/Resources/icons/player_volume_small@3x.png new file mode 100644 index 000000000..a10b418ae Binary files /dev/null and b/Telegram/Resources/icons/player_volume_small@3x.png differ diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 3d8a71a2a..1629b6a89 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -2104,6 +2104,8 @@ bool OverlayWidget::initStreaming(bool continueStreaming) { || (!_streamed->instance.player().active() && !_streamed->instance.player().finished())) { startStreamingPlayer(); + } else { + updatePlaybackState(); } return true; } diff --git a/Telegram/SourceFiles/media/view/media_view_pip.cpp b/Telegram/SourceFiles/media/view/media_view_pip.cpp index 275336f5b..54163ab1d 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.cpp +++ b/Telegram/SourceFiles/media/view/media_view_pip.cpp @@ -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 @@ -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(&_panel, st::mediaviewPlayButton)) -, _pictureInPicture( - std::in_place, - &_panel, - object_ptr(&_panel, st::mediaviewFullScreenButton)) -, _close( - std::in_place, - &_panel, - object_ptr(&_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 e) { - return e->type() == QEvent::Close; - }) | rpl::start_with_next([=] { - crl::on_main(&_panel, [=] { - _destroy(); - }); + ) | rpl::start_with_next([=](not_null e) { + switch (e->type()) { + case QEvent::Close: handleClose(); break; + case QEvent::Leave: handleLeave(); break; + case QEvent::MouseMove: + handleMouseMove(static_cast(e.get())->pos()); + break; + case QEvent::MouseButtonPress: + handleMousePress(static_cast(e.get())->button()); + break; + case QEvent::MouseButtonRelease: + handleMouseRelease(static_cast(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() { } diff --git a/Telegram/SourceFiles/media/view/media_view_pip.h b/Telegram/SourceFiles/media/view/media_view_pip.h index cd1249dc9..7ad917029 100644 --- a/Telegram/SourceFiles/media/view/media_view_pip.h +++ b/Telegram/SourceFiles/media/view/media_view_pip.h @@ -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 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; Streaming::Instance _instance; PipPanel _panel; QSize _size; - base::unique_qptr> _playPauseResume; - base::unique_qptr< Ui::FadeWrap> _pictureInPicture; - base::unique_qptr< Ui::FadeWrap> _close; bool _showPause = false; + OverState _over = OverState::None; + std::optional _pressed; + Button _close; + Button _enlarge; + Button _playback; + Button _play; + Ui::Animations::Simple _controlsShown; FnMut _closeAndContinue; FnMut _destroy; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp index 3fde55bfb..4ccc929e2 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp @@ -31,10 +31,9 @@ PlaybackControls::PlaybackControls( , _playbackProgress(std::make_unique()) , _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(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(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); diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.h b/Telegram/SourceFiles/media/view/media_view_playback_controls.h index e2d20b887..31fed6214 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.h +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.h @@ -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 _receivedTillProgress; object_ptr _volumeToggle; object_ptr _volumeController; - object_ptr _speedController; - object_ptr _speedLabel; + object_ptr _menuToggle; object_ptr _fullScreenToggle; object_ptr _pictureInPicture; object_ptr _playedAlready; diff --git a/Telegram/SourceFiles/media/view/mediaview.style b/Telegram/SourceFiles/media/view/mediaview.style index 40edc751a..211e02ece 100644 --- a/Telegram/SourceFiles/media/view/mediaview.style +++ b/Telegram/SourceFiles/media/view/mediaview.style @@ -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; \ No newline at end of file +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 }};