diff --git a/Telegram/Resources/icons/player/player_settings.png b/Telegram/Resources/icons/player/player_settings.png new file mode 100644 index 000000000..65a420de0 Binary files /dev/null and b/Telegram/Resources/icons/player/player_settings.png differ diff --git a/Telegram/Resources/icons/player/player_settings@2x.png b/Telegram/Resources/icons/player/player_settings@2x.png new file mode 100644 index 000000000..af78b2666 Binary files /dev/null and b/Telegram/Resources/icons/player/player_settings@2x.png differ diff --git a/Telegram/Resources/icons/player/player_settings@3x.png b/Telegram/Resources/icons/player/player_settings@3x.png new file mode 100644 index 000000000..da1ec8c72 Binary files /dev/null and b/Telegram/Resources/icons/player/player_settings@3x.png differ diff --git a/Telegram/SourceFiles/media/player/media_player_button.cpp b/Telegram/SourceFiles/media/player/media_player_button.cpp index 0e9ab424a..a42929211 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.cpp +++ b/Telegram/SourceFiles/media/player/media_player_button.cpp @@ -307,7 +307,7 @@ SpeedButton::SpeedButton(QWidget *parent, const style::MediaSpeedButton &st) resize(_st.size); } -void SpeedButton::setSpeed(float64 speed, anim::type animated) { +void SpeedButton::setSpeed(float64 speed) { _isDefault = EqualSpeeds(speed, 1.); _layout.setSpeed(speed); update(); @@ -337,4 +337,86 @@ QImage SpeedButton::prepareRippleMask() const { _st.rippleRadius); } +SettingsButton::SettingsButton( + QWidget *parent, + const style::MediaSpeedButton &st) +: RippleButton(parent, st.ripple) +, _st(st) +, _isDefaultSpeed(true) { + resize(_st.size); +} + +void SettingsButton::setSpeed(float64 speed) { + _isDefaultSpeed = EqualSpeeds(speed, 1.); + update(); +} + +void SettingsButton::setQuality(int quality) { + update(); +} + +void SettingsButton::setActive(bool active) { + if (_active == active) { + return; + } + _active = active; + _activeAnimation.start([=] { + update(); + }, active ? 0. : 1., active ? 1. : 0., crl::time(150)); +} + +void SettingsButton::paintEvent(QPaintEvent *e) { + auto p = QPainter(this); + + paintRipple( + p, + QPoint(_st.padding.left(), _st.padding.top()), + _isDefaultSpeed ? nullptr : &_st.rippleActiveColor->c); + + //const auto active = !_isDefaultSpeed; + const auto inner = QRect( + QPoint(), + _st.size + ).marginsRemoved(_st.padding); + + auto hq = std::optional(); + const auto active = _activeAnimation.value(_active ? 1. : 0.); + if (active > 0.) { + const auto shift = QRectF(inner).center(); + p.save(); + p.translate(shift); + p.rotate(active * 60.); + p.translate(-shift); + hq.emplace(p); + } + _st.icon.paintInCenter(p, inner); + if (active > 0.) { + p.restore(); + hq.reset(); + } + + //p.setPen(color); + //p.setFont(_st.font); + + //p.drawText( + // QPointF(inner.topLeft()) + QPointF( + // (inner.width() - _textWidth) / 2., + // (inner.height() - _adjustedHeight) / 2. + _adjustedAscent), + // _text); +} + +QPoint SettingsButton::prepareRippleStartPosition() const { + const auto inner = rect().marginsRemoved(_st.padding); + const auto result = mapFromGlobal(QCursor::pos()) - inner.topLeft(); + return inner.contains(result) + ? result + : DisabledRippleStartPosition(); +} + +QImage SettingsButton::prepareRippleMask() const { + return Ui::RippleAnimation::RoundRectMask( + rect().marginsRemoved(_st.padding).size(), + _st.rippleRadius); +} + } // namespace Media::Player diff --git a/Telegram/SourceFiles/media/player/media_player_button.h b/Telegram/SourceFiles/media/player/media_player_button.h index 750b533eb..8709c0cdd 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.h +++ b/Telegram/SourceFiles/media/player/media_player_button.h @@ -87,7 +87,7 @@ public: return _st; } - void setSpeed(float64 speed, anim::type animated = anim::type::normal); + void setSpeed(float64 speed); private: void paintEvent(QPaintEvent *e) override; @@ -101,4 +101,29 @@ private: }; +class SettingsButton final : public Ui::RippleButton { +public: + SettingsButton(QWidget *parent, const style::MediaSpeedButton &st); + + [[nodiscard]] const style::MediaSpeedButton &st() const { + return _st; + } + + void setSpeed(float64 speed); + void setQuality(int quality); + void setActive(bool active); + +private: + void paintEvent(QPaintEvent *e) override; + + QPoint prepareRippleStartPosition() const override; + QImage prepareRippleMask() const override; + + const style::MediaSpeedButton &_st; + Ui::Animations::Simple _activeAnimation; + bool _isDefaultSpeed = false; + bool _active = false; + +}; + } // namespace Media::Player diff --git a/Telegram/SourceFiles/media/player/media_player_dropdown.cpp b/Telegram/SourceFiles/media/player/media_player_dropdown.cpp index 843ce1553..45e4e2c04 100644 --- a/Telegram/SourceFiles/media/player/media_player_dropdown.cpp +++ b/Telegram/SourceFiles/media/player/media_player_dropdown.cpp @@ -558,6 +558,10 @@ void WithDropdownController::updateDropdownGeometry() { _menu->move(position); } +rpl::producer WithDropdownController::menuToggledValue() const { + return _menuToggled.value(); +} + void WithDropdownController::hideTemporarily() { if (_menu && !_menu->isHidden()) { _temporarilyHidden = true; @@ -590,10 +594,20 @@ void WithDropdownController::showMenu() { } }, _menu->lifetime()); _menu->setHiddenCallback([=]{ + if (_menu.get() == raw) { + _menuToggled = false; + } Ui::PostponeCall(raw, [this] { _menu = nullptr; + _menuToggled = false; }); }); + _menu->setShowStartCallback([=] { + _menuToggled = true; + }); + _menu->setHideStartCallback([=] { + _menuToggled = false; + }); _button->installEventFilter(raw); fillMenu(raw); updateDropdownGeometry(); @@ -608,6 +622,7 @@ void WithDropdownController::showMenu() { Unexpected("Menu align value."); }(); _menu->showAnimated(origin); + _menuToggled = true; } OrderController::OrderController( @@ -695,7 +710,8 @@ void OrderController::updateIcon() { } SpeedController::SpeedController( - not_null button, + not_null button, + const style::MediaSpeedButton &st, not_null menuParent, Fn menuOverCallback, Fn value, @@ -706,10 +722,10 @@ SpeedController::SpeedController( : WithDropdownController( button, menuParent, - button->st().menu.dropdown, - button->st().menuAlign, + st.menu.dropdown, + st.menuAlign, std::move(menuOverCallback)) -, _st(button->st()) +, _st(st) , _lookup(std::move(value)) , _change(std::move(change)) , _qualities(std::move(qualities)) @@ -727,20 +743,16 @@ SpeedController::SpeedController( setSpeed(_lookup(false)); _speed = _lookup(true); - - button->setSpeed(_speed, anim::type::instant); - - _speedChanged.events_starting_with( - speed() - ) | rpl::start_with_next([=](float64 speed) { - button->setSpeed(speed); - }, button->lifetime()); } rpl::producer<> SpeedController::saved() const { return _saved.events(); } +rpl::producer SpeedController::realtimeValue() const { + return _speedChanged.events_starting_with(speed()); +} + float64 SpeedController::speed() const { return _isDefault ? 1. : _speed; } diff --git a/Telegram/SourceFiles/media/player/media_player_dropdown.h b/Telegram/SourceFiles/media/player/media_player_dropdown.h index 7fcdc1f29..7975677ff 100644 --- a/Telegram/SourceFiles/media/player/media_player_dropdown.h +++ b/Telegram/SourceFiles/media/player/media_player_dropdown.h @@ -30,8 +30,6 @@ class Menu; namespace Media::Player { -class SpeedButton; - class Dropdown final : public Ui::RpWidget { public: explicit Dropdown(QWidget *parent); @@ -82,6 +80,7 @@ public: Ui::DropdownMenu *menu() const; void updateDropdownGeometry(); + [[nodiscard]] rpl::producer menuToggledValue() const; void hideTemporarily(); void showBack(); @@ -98,6 +97,7 @@ private: const Qt::Alignment _menuAlign = Qt::AlignTop | Qt::AlignRight; const Fn _menuOverCallback; base::unique_qptr _menu; + rpl::variable _menuToggled; bool _temporarilyHidden = false; bool _overButton = false; @@ -125,7 +125,8 @@ private: class SpeedController final : public WithDropdownController { public: SpeedController( - not_null button, + not_null button, + const style::MediaSpeedButton &st, not_null menuParent, Fn menuOverCallback, Fn value, @@ -135,6 +136,7 @@ public: Fn changeQuality = nullptr); [[nodiscard]] rpl::producer<> saved() const; + [[nodiscard]] rpl::producer realtimeValue() const; private: void fillMenu(not_null menu) override; diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index a74be5945..6425b7951 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -73,10 +73,17 @@ Widget::Widget( , _speedController( std::make_unique( _speedToggle.data(), + _speedToggle->st(), dropdownsParent, [=](bool over) { markOver(over); }, [=](bool lastNonDefault) { return speedLookup(lastNonDefault); }, [=](float64 speed) { saveSpeed(speed); })) { + _speedController->realtimeValue( + ) | rpl::start_with_next([=](float64 speed) { + _speedToggle->setSpeed(speed); + }, _speedToggle->lifetime()); + _speedToggle->finishAnimating(); + setAttribute(Qt::WA_OpaquePaintEvent); setMouseTracking(true); resize(width(), st::mediaPlayerHeight + st::lineWidth); diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 3c3ae5fbf..55efb6fcc 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -354,7 +354,7 @@ mediaviewSpeedButton: MediaSpeedButton(mediaPlayerSpeedButton) { fg: mediaviewPlaybackIconFg; overFg: mediaviewPlaybackIconFgOver; activeFg: mediaviewTextLinkFg; - icon: icon{{ "player/player_speed", mediaviewPlaybackIconFg }}; + icon: icon{{ "player/player_settings", mediaviewPlaybackIconFg }}; ripple: RippleAnimation(defaultRippleAnimation) { color: mediaviewPlaybackIconRipple; } diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp index 8ec6bd86c..ac46c78db 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp @@ -36,7 +36,7 @@ PlaybackControls::PlaybackControls( , _volumeController(this, st::mediaviewPlayback) , _speedToggle((Media::Audio::SupportsSpeedControl() || !_delegate->playbackControlsQualities().empty()) - ? object_ptr(this, st::mediaviewSpeedButton) + ? object_ptr(this, st::mediaviewSpeedButton) : nullptr) , _fullScreenToggle(this, st::mediaviewFullScreenButton) , _pictureInPicture(this, st::mediaviewPipButton) @@ -45,6 +45,7 @@ PlaybackControls::PlaybackControls( , _speedController(_speedToggle ? std::make_unique( _speedToggle.data(), + _speedToggle->st(), parent, [=](bool) {}, [=](bool lastNonDefault) { return speedLookup(lastNonDefault); }, @@ -62,6 +63,11 @@ PlaybackControls::PlaybackControls( fadeUpdated(opacity); }); + _speedController->menuToggledValue( + ) | rpl::start_with_next([=](bool toggled) { + _speedToggle->setActive(toggled); + }, _speedToggle->lifetime()); + _pictureInPicture->addClickHandler([=] { _delegate->playbackControlsToPictureInPicture(); }); @@ -193,10 +199,12 @@ float64 PlaybackControls::speedLookup(bool lastNonDefault) const { } void PlaybackControls::saveSpeed(float64 speed) { + _speedToggle->setSpeed(speed); _delegate->playbackControlsSpeedChanged(speed); } void PlaybackControls::saveQuality(int quality) { + _speedToggle->setQuality(quality); _delegate->playbackControlsQualityChanged(quality); } diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.h b/Telegram/SourceFiles/media/view/media_view_playback_controls.h index 0970808c8..5357fb2fe 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.h +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.h @@ -21,7 +21,7 @@ class PopupMenu; namespace Media { namespace Player { struct TrackState; -class SpeedButton; +class SettingsButton; class SpeedController; } // namespace Player @@ -114,7 +114,7 @@ private: std::unique_ptr _receivedTillProgress; object_ptr _volumeToggle; object_ptr _volumeController; - object_ptr _speedToggle; + object_ptr _speedToggle; object_ptr _fullScreenToggle; object_ptr _pictureInPicture; object_ptr _playedAlready;