diff --git a/Telegram/Resources/icons/player/player_check.png b/Telegram/Resources/icons/player/player_check.png index cdba65b47..285a76b88 100644 Binary files a/Telegram/Resources/icons/player/player_check.png and b/Telegram/Resources/icons/player/player_check.png differ diff --git a/Telegram/Resources/icons/player/player_check@2x.png b/Telegram/Resources/icons/player/player_check@2x.png index 9d432032b..7a51614af 100644 Binary files a/Telegram/Resources/icons/player/player_check@2x.png and b/Telegram/Resources/icons/player/player_check@2x.png differ diff --git a/Telegram/Resources/icons/player/player_check@3x.png b/Telegram/Resources/icons/player/player_check@3x.png index 097ad06c5..c9cc4b1c7 100644 Binary files a/Telegram/Resources/icons/player/player_check@3x.png and b/Telegram/Resources/icons/player/player_check@3x.png differ diff --git a/Telegram/Resources/icons/player/player_fullscreen.png b/Telegram/Resources/icons/player/player_fullscreen.png index bb3bbd363..29f7b1b62 100644 Binary files a/Telegram/Resources/icons/player/player_fullscreen.png and b/Telegram/Resources/icons/player/player_fullscreen.png differ diff --git a/Telegram/Resources/icons/player/player_fullscreen@2x.png b/Telegram/Resources/icons/player/player_fullscreen@2x.png index 79abf0a88..8380f1859 100644 Binary files a/Telegram/Resources/icons/player/player_fullscreen@2x.png and b/Telegram/Resources/icons/player/player_fullscreen@2x.png differ diff --git a/Telegram/Resources/icons/player/player_fullscreen@3x.png b/Telegram/Resources/icons/player/player_fullscreen@3x.png index 9354611f5..77ebb58bd 100644 Binary files a/Telegram/Resources/icons/player/player_fullscreen@3x.png and b/Telegram/Resources/icons/player/player_fullscreen@3x.png differ diff --git a/Telegram/Resources/icons/player/player_minimize.png b/Telegram/Resources/icons/player/player_minimize.png index a4d648eb7..662c532ec 100644 Binary files a/Telegram/Resources/icons/player/player_minimize.png and b/Telegram/Resources/icons/player/player_minimize.png differ diff --git a/Telegram/Resources/icons/player/player_minimize@2x.png b/Telegram/Resources/icons/player/player_minimize@2x.png index efbd5b0c9..13c175a35 100644 Binary files a/Telegram/Resources/icons/player/player_minimize@2x.png and b/Telegram/Resources/icons/player/player_minimize@2x.png differ diff --git a/Telegram/Resources/icons/player/player_minimize@3x.png b/Telegram/Resources/icons/player/player_minimize@3x.png index 16367d5d6..4fde439dd 100644 Binary files a/Telegram/Resources/icons/player/player_minimize@3x.png and b/Telegram/Resources/icons/player/player_minimize@3x.png differ diff --git a/Telegram/Resources/icons/player/player_more.png b/Telegram/Resources/icons/player/player_more.png index b61a629d8..a0603fb43 100644 Binary files a/Telegram/Resources/icons/player/player_more.png and b/Telegram/Resources/icons/player/player_more.png differ diff --git a/Telegram/Resources/icons/player/player_more@2x.png b/Telegram/Resources/icons/player/player_more@2x.png index 0fd9fdab2..d729c2305 100644 Binary files a/Telegram/Resources/icons/player/player_more@2x.png and b/Telegram/Resources/icons/player/player_more@2x.png differ diff --git a/Telegram/Resources/icons/player/player_more@3x.png b/Telegram/Resources/icons/player/player_more@3x.png index 0ca0520d6..3ca179488 100644 Binary files a/Telegram/Resources/icons/player/player_more@3x.png and b/Telegram/Resources/icons/player/player_more@3x.png differ diff --git a/Telegram/Resources/icons/player/player_pause.png b/Telegram/Resources/icons/player/player_pause.png index b40213cbb..99c9207f1 100644 Binary files a/Telegram/Resources/icons/player/player_pause.png and b/Telegram/Resources/icons/player/player_pause.png differ diff --git a/Telegram/Resources/icons/player/player_pause@2x.png b/Telegram/Resources/icons/player/player_pause@2x.png index a8e819654..74538bd9f 100644 Binary files a/Telegram/Resources/icons/player/player_pause@2x.png and b/Telegram/Resources/icons/player/player_pause@2x.png differ diff --git a/Telegram/Resources/icons/player/player_pause@3x.png b/Telegram/Resources/icons/player/player_pause@3x.png index 71d9fd6eb..7913d8741 100644 Binary files a/Telegram/Resources/icons/player/player_pause@3x.png and b/Telegram/Resources/icons/player/player_pause@3x.png differ diff --git a/Telegram/Resources/icons/player/player_pip.png b/Telegram/Resources/icons/player/player_pip.png index 52e167ba1..155555bbd 100644 Binary files a/Telegram/Resources/icons/player/player_pip.png and b/Telegram/Resources/icons/player/player_pip.png differ diff --git a/Telegram/Resources/icons/player/player_pip@2x.png b/Telegram/Resources/icons/player/player_pip@2x.png index bfa8e10f7..d37c609ad 100644 Binary files a/Telegram/Resources/icons/player/player_pip@2x.png and b/Telegram/Resources/icons/player/player_pip@2x.png differ diff --git a/Telegram/Resources/icons/player/player_pip@3x.png b/Telegram/Resources/icons/player/player_pip@3x.png index cf0cd7990..d921c88c5 100644 Binary files a/Telegram/Resources/icons/player/player_pip@3x.png and b/Telegram/Resources/icons/player/player_pip@3x.png differ diff --git a/Telegram/Resources/icons/player/player_play.png b/Telegram/Resources/icons/player/player_play.png index 816e5ef1e..449760247 100644 Binary files a/Telegram/Resources/icons/player/player_play.png and b/Telegram/Resources/icons/player/player_play.png differ diff --git a/Telegram/Resources/icons/player/player_play@2x.png b/Telegram/Resources/icons/player/player_play@2x.png index a4e130c4a..152d34fd8 100644 Binary files a/Telegram/Resources/icons/player/player_play@2x.png and b/Telegram/Resources/icons/player/player_play@2x.png differ diff --git a/Telegram/Resources/icons/player/player_play@3x.png b/Telegram/Resources/icons/player/player_play@3x.png index 0a101f3f6..35bbf5c53 100644 Binary files a/Telegram/Resources/icons/player/player_play@3x.png and b/Telegram/Resources/icons/player/player_play@3x.png differ diff --git a/Telegram/Resources/icons/player/player_volume_off.png b/Telegram/Resources/icons/player/player_volume_off.png index 88ed4e391..0e5c893ba 100644 Binary files a/Telegram/Resources/icons/player/player_volume_off.png and b/Telegram/Resources/icons/player/player_volume_off.png differ diff --git a/Telegram/Resources/icons/player/player_volume_off@2x.png b/Telegram/Resources/icons/player/player_volume_off@2x.png index 267bcc6f7..dcc4f69f3 100644 Binary files a/Telegram/Resources/icons/player/player_volume_off@2x.png and b/Telegram/Resources/icons/player/player_volume_off@2x.png differ diff --git a/Telegram/Resources/icons/player/player_volume_off@3x.png b/Telegram/Resources/icons/player/player_volume_off@3x.png index 9556ac795..4d2c5c6f9 100644 Binary files a/Telegram/Resources/icons/player/player_volume_off@3x.png and b/Telegram/Resources/icons/player/player_volume_off@3x.png differ diff --git a/Telegram/Resources/icons/player/player_volume_on.png b/Telegram/Resources/icons/player/player_volume_on.png index eaddd3674..8aff2e4da 100644 Binary files a/Telegram/Resources/icons/player/player_volume_on.png and b/Telegram/Resources/icons/player/player_volume_on.png differ diff --git a/Telegram/Resources/icons/player/player_volume_on@2x.png b/Telegram/Resources/icons/player/player_volume_on@2x.png index f931fe241..77bf6b06b 100644 Binary files a/Telegram/Resources/icons/player/player_volume_on@2x.png and b/Telegram/Resources/icons/player/player_volume_on@2x.png differ diff --git a/Telegram/Resources/icons/player/player_volume_on@3x.png b/Telegram/Resources/icons/player/player_volume_on@3x.png index 5d10c66a6..c868accca 100644 Binary files a/Telegram/Resources/icons/player/player_volume_on@3x.png and b/Telegram/Resources/icons/player/player_volume_on@3x.png differ diff --git a/Telegram/Resources/icons/player/player_volume_small.png b/Telegram/Resources/icons/player/player_volume_small.png index 8cbcaf5c4..0365afa33 100644 Binary files a/Telegram/Resources/icons/player/player_volume_small.png and b/Telegram/Resources/icons/player/player_volume_small.png differ diff --git a/Telegram/Resources/icons/player/player_volume_small@2x.png b/Telegram/Resources/icons/player/player_volume_small@2x.png index 3098bed94..25ad96230 100644 Binary files a/Telegram/Resources/icons/player/player_volume_small@2x.png and b/Telegram/Resources/icons/player/player_volume_small@2x.png differ diff --git a/Telegram/Resources/icons/player/player_volume_small@3x.png b/Telegram/Resources/icons/player/player_volume_small@3x.png index a10b418ae..3cd717371 100644 Binary files a/Telegram/Resources/icons/player/player_volume_small@3x.png and b/Telegram/Resources/icons/player/player_volume_small@3x.png differ diff --git a/Telegram/SourceFiles/core/core_settings.cpp b/Telegram/SourceFiles/core/core_settings.cpp index 97400a7d2..d1e9bfb5a 100644 --- a/Telegram/SourceFiles/core/core_settings.cpp +++ b/Telegram/SourceFiles/core/core_settings.cpp @@ -15,7 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/platform/base_platform_info.h" #include "webrtc/webrtc_create_adm.h" #include "media/player/media_player_instance.h" -#include "media/audio/media_audio.h" +#include "media/media_common.h" #include "ui/gl/gl_detection.h" #include "calls/group/calls_group_common.h" #include "spellcheck/spellcheck_types.h" @@ -119,10 +119,6 @@ void LogPosition(const WindowPosition &position, const QString &name) { return position; } -float64 Settings::PlaybackSpeed::Default() { - return Media::Audio::kSpedUpDefault; -} - Settings::Settings() : _sendSubmitWay(Ui::InputSubmitSettings::Enter) , _floatPlayerColumn(Window::Column::Second) @@ -814,17 +810,17 @@ void Settings::addFromSerialized(const QByteArray &serialized) { _closeToTaskbar = (closeToTaskbar == 1); _customDeviceModel = customDeviceModel; _accountsOrder = accountsOrder; - const auto uncheckedPlayerRepeatMode = static_cast(playerRepeatMode); + const auto uncheckedPlayerRepeatMode = static_cast(playerRepeatMode); switch (uncheckedPlayerRepeatMode) { - case Media::Player::RepeatMode::None: - case Media::Player::RepeatMode::One: - case Media::Player::RepeatMode::All: _playerRepeatMode = uncheckedPlayerRepeatMode; break; + case Media::RepeatMode::None: + case Media::RepeatMode::One: + case Media::RepeatMode::All: _playerRepeatMode = uncheckedPlayerRepeatMode; break; } - const auto uncheckedPlayerOrderMode = static_cast(playerOrderMode); + const auto uncheckedPlayerOrderMode = static_cast(playerOrderMode); switch (uncheckedPlayerOrderMode) { - case Media::Player::OrderMode::Default: - case Media::Player::OrderMode::Reverse: - case Media::Player::OrderMode::Shuffle: _playerOrderMode = uncheckedPlayerOrderMode; break; + case Media::OrderMode::Default: + case Media::OrderMode::Reverse: + case Media::OrderMode::Shuffle: _playerOrderMode = uncheckedPlayerOrderMode; break; } _macWarnBeforeQuit = (macWarnBeforeQuit == 1); _hardwareAcceleratedVideo = (hardwareAcceleratedVideo == 1); @@ -1178,7 +1174,7 @@ float64 Settings::DefaultDialogsWidthRatio() { } qint32 Settings::SerializePlaybackSpeed(PlaybackSpeed speed) { - using namespace Media::Audio; + using namespace Media; const auto value = int(base::SafeRound( std::clamp(speed.value, kSpeedMin, kSpeedMax) * 100)); @@ -1186,7 +1182,7 @@ qint32 Settings::SerializePlaybackSpeed(PlaybackSpeed speed) { } auto Settings::DeserializePlaybackSpeed(qint32 speed) -> PlaybackSpeed { - using namespace Media::Audio; + using namespace Media; auto enabled = true; const auto validate = [&](float64 result) { diff --git a/Telegram/SourceFiles/core/core_settings.h b/Telegram/SourceFiles/core/core_settings.h index df447d307..a693c6748 100644 --- a/Telegram/SourceFiles/core/core_settings.h +++ b/Telegram/SourceFiles/core/core_settings.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "core/core_settings_proxy.h" +#include "media/media_common.h" #include "window/themes/window_themes_embedded.h" #include "ui/chat/attach/attach_send_files_way.h" #include "platform/platform_notifications_manager.h" @@ -37,11 +38,6 @@ namespace Calls::Group { enum class StickedTooltip; } // namespace Calls::Group -namespace Media::Player { -enum class RepeatMode; -enum class OrderMode; -} // namespace Media::Player - namespace Core { struct WindowPosition { @@ -718,28 +714,28 @@ public: [[nodiscard]] rpl::producer deviceModelChanges() const; [[nodiscard]] rpl::producer deviceModelValue() const; - void setPlayerRepeatMode(Media::Player::RepeatMode mode) { + void setPlayerRepeatMode(Media::RepeatMode mode) { _playerRepeatMode = mode; } - [[nodiscard]] Media::Player::RepeatMode playerRepeatMode() const { + [[nodiscard]] Media::RepeatMode playerRepeatMode() const { return _playerRepeatMode.current(); } - [[nodiscard]] rpl::producer playerRepeatModeValue() const { + [[nodiscard]] rpl::producer playerRepeatModeValue() const { return _playerRepeatMode.value(); } - [[nodiscard]] rpl::producer playerRepeatModeChanges() const { + [[nodiscard]] rpl::producer playerRepeatModeChanges() const { return _playerRepeatMode.changes(); } - void setPlayerOrderMode(Media::Player::OrderMode mode) { + void setPlayerOrderMode(Media::OrderMode mode) { _playerOrderMode = mode; } - [[nodiscard]] Media::Player::OrderMode playerOrderMode() const { + [[nodiscard]] Media::OrderMode playerOrderMode() const { return _playerOrderMode.current(); } - [[nodiscard]] rpl::producer playerOrderModeValue() const { + [[nodiscard]] rpl::producer playerOrderModeValue() const { return _playerOrderMode.value(); } - [[nodiscard]] rpl::producer playerOrderModeChanges() const { + [[nodiscard]] rpl::producer playerOrderModeChanges() const { return _playerOrderMode.changes(); } [[nodiscard]] std::vector accountsOrder() const { @@ -811,9 +807,7 @@ public: [[nodiscard]] static float64 DefaultDialogsWidthRatio(); struct PlaybackSpeed { - [[nodiscard]] static float64 Default(); - - float64 value = Default(); + float64 value = Media::kSpedUpDefault; bool enabled = false; }; [[nodiscard]] static qint32 SerializePlaybackSpeed(PlaybackSpeed speed); @@ -909,8 +903,8 @@ private: base::flags _hiddenGroupCallTooltips; rpl::variable _closeToTaskbar = false; rpl::variable _customDeviceModel; - rpl::variable _playerRepeatMode; - rpl::variable _playerOrderMode; + rpl::variable _playerRepeatMode; + rpl::variable _playerOrderMode; bool _macWarnBeforeQuit = true; std::vector _accountsOrder; #ifdef Q_OS_MAC diff --git a/Telegram/SourceFiles/media/audio/media_audio.cpp b/Telegram/SourceFiles/media/audio/media_audio.cpp index ee5303374..9c6e873a0 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio.cpp @@ -491,7 +491,7 @@ void Mixer::Track::updateWithSpeedPosition() { int64 Mixer::Track::SpeedIndependentPosition( int64 position, float64 speed) { - Expects(speed <= Audio::kSpeedMax); + Expects(speed <= kSpeedMax); return int64(base::SafeRound(position * speed)); } @@ -499,7 +499,7 @@ int64 Mixer::Track::SpeedIndependentPosition( int64 Mixer::Track::SpeedDependentPosition( int64 position, float64 speed) { - Expects(speed >= Audio::kSpeedMin); + Expects(speed >= kSpeedMin); return int64(base::SafeRound(position / speed)); } diff --git a/Telegram/SourceFiles/media/audio/media_audio.h b/Telegram/SourceFiles/media/audio/media_audio.h index 920cd1379..d44b33f8e 100644 --- a/Telegram/SourceFiles/media/audio/media_audio.h +++ b/Telegram/SourceFiles/media/audio/media_audio.h @@ -35,10 +35,6 @@ namespace Audio { class Instance; -inline constexpr auto kSpeedMin = 0.5; -inline constexpr auto kSpeedMax = 2.5; -inline constexpr auto kSpedUpDefault = 1.7; - // Thread: Main. void Start(not_null instance); void Finish(not_null instance); diff --git a/Telegram/SourceFiles/media/audio/media_audio_ffmpeg_loader.cpp b/Telegram/SourceFiles/media/audio/media_audio_ffmpeg_loader.cpp index f9110b2f3..5f3fc7d41 100644 --- a/Telegram/SourceFiles/media/audio/media_audio_ffmpeg_loader.cpp +++ b/Telegram/SourceFiles/media/audio/media_audio_ffmpeg_loader.cpp @@ -7,9 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "media/audio/media_audio_ffmpeg_loader.h" +#include "base/bytes.h" #include "core/file_location.h" #include "ffmpeg/ffmpeg_utility.h" -#include "base/bytes.h" +#include "media/media_common.h" extern "C" { #include @@ -540,7 +541,7 @@ bool AbstractAudioFFMpegLoader::ensureResampleSpaceAvailable(int samples) { } bool AbstractAudioFFMpegLoader::changeSpeedFilter(float64 speed) { - speed = std::clamp(speed, Audio::kSpeedMin, Audio::kSpeedMax); + speed = std::clamp(speed, kSpeedMin, kSpeedMax); if (_filterSpeed == speed) { return false; } diff --git a/Telegram/SourceFiles/media/media_common.h b/Telegram/SourceFiles/media/media_common.h new file mode 100644 index 000000000..73f99109f --- /dev/null +++ b/Telegram/SourceFiles/media/media_common.h @@ -0,0 +1,28 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Media { + +enum class RepeatMode { + None, + One, + All, +}; + +enum class OrderMode { + Default, + Reverse, + Shuffle, +}; + +inline constexpr auto kSpeedMin = 0.5; +inline constexpr auto kSpeedMax = 2.5; +inline constexpr auto kSpedUpDefault = 1.7; + +} // namespace Media diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style index f26a53945..df65e4fe2 100644 --- a/Telegram/SourceFiles/media/player/media_player.style +++ b/Telegram/SourceFiles/media/player/media_player.style @@ -27,31 +27,42 @@ MediaPlayerButton { duration: int; } -MediaSpeedButton { - width: pixels; - height: pixels; - font: font; - icon: icon; -} - MediaSpeedMenu { - menu: Menu; - iconFg: color; - iconFgActive: color; - textFgActive: color; + dropdown: DropdownMenu; activeCheck: icon; activeCheckSkip: pixels; sliderStyle: TextStyle; sliderPadding: margins; sliderWidth: pixels; slider: MediaSlider; + + slow: icon; + slowActive: icon; + normal: icon; + normalActive: icon; + medium: icon; + mediumActive: icon; + fast: icon; + fastActive: icon; + veryFast: icon; + veryFastActive: icon; + superFast: icon; + superFastActive: icon; } -mediaSpeedButton: MediaSpeedButton { - width: 24px; - height: 24px; - font: font(11px semibold); - icon: icon{{ "player/player_speed", menuIconFg }}; +MediaSpeedButton { + size: size; + padding: margins; + font: font; + fg: color; + overFg: color; + activeFg: color; + icon: icon; + ripple: RippleAnimation; + rippleActiveColor: color; + rippleRadius: pixels; + menu: MediaSpeedMenu; + menuAlign: align; } mediaPlayerButton: MediaPlayerButton { @@ -142,13 +153,6 @@ mediaPlayerCancelIcon: icon{ { "player/panel_close", mediaPlayerActiveFg } }; -mediaPlayerSpeedSize: size(30px, 30px); -mediaPlayerSpeedRadius: 4px; -mediaPlayerSpeedRipple: RippleAnimation(defaultRippleAnimation) { - color: lightButtonBgOver; -} -mediaPlayerSpeedDisabledRippleBg: windowBgOver; - mediaPlayerMenu: DropdownMenu(defaultDropdownMenu) { wrap: InnerDropdown(defaultInnerDropdown) { scrollPadding: margins(0px, 4px, 0px, 4px); @@ -157,18 +161,17 @@ mediaPlayerMenu: DropdownMenu(defaultDropdownMenu) { } mediaPlayerMenuCheck: icon {{ "player/player_check", mediaPlayerActiveFg }}; -mediaSpeedMenu: MediaSpeedMenu { - menu: Menu(menuWithIcons) { - separator: MenuSeparator(defaultMenuSeparator) { - padding: margins(0px, 4px, 0px, 4px); - width: 6px; +mediaPlayerSpeedMenu: MediaSpeedMenu { + dropdown: DropdownMenu(mediaPlayerMenu) { + menu: Menu(menuWithIcons) { + separator: MenuSeparator(defaultMenuSeparator) { + padding: margins(0px, 4px, 0px, 4px); + width: 6px; + } + itemPadding: margins(54px, 7px, 54px, 9px); + itemFgDisabled: mediaPlayerActiveFg; } - itemPadding: margins(54px, 7px, 54px, 9px); - itemFgDisabled: mediaPlayerActiveFg; } - iconFg: menuIconColor; - iconFgActive: mediaPlayerActiveFg; - textFgActive: mediaPlayerActiveFg; activeCheck: mediaPlayerMenuCheck; activeCheckSkip: 8px; sliderStyle: TextStyle(defaultTextStyle) { @@ -186,19 +189,37 @@ mediaSpeedMenu: MediaSpeedMenu { width: 6px; seekSize: size(6px, 6px); } + + slow: playerSpeedSlow; + slowActive: playerSpeedSlowActive; + normal: playerSpeedNormal; + normalActive: playerSpeedNormalActive; + medium: playerSpeedMedium; + mediumActive: playerSpeedMediumActive; + fast: playerSpeedFast; + fastActive: playerSpeedFastActive; + veryFast: playerSpeedVeryFast; + veryFastActive: playerSpeedVeryFastActive; + superFast: playerSpeedSuperFast; + superFastActive: playerSpeedSuperFastActive; +} + +mediaPlayerSpeedButton: MediaSpeedButton { + size: size(30px, 30px); + padding: margins(0px, 6px, 0px, 0px); + font: font(11px bold); + fg: menuIconFg; + overFg: menuIconFgOver; + activeFg: mediaPlayerActiveFg; + icon: icon{{ "player/player_speed", menuIconFg }}; + ripple: RippleAnimation(defaultRippleAnimation) { + color: windowBgOver; + } + rippleActiveColor: lightButtonBgOver; + rippleRadius: 4px; + menu: mediaPlayerSpeedMenu; + menuAlign: align(topright); } -mediaSpeedSlow: icon {{ "player/speed/audiospeed_menu_0.5", menuIconColor }}; -mediaSpeedSlowActive: icon {{ "player/speed/audiospeed_menu_0.5", mediaPlayerActiveFg }}; -mediaSpeedNormal: icon {{ "player/speed/audiospeed_menu_1.0", menuIconColor }}; -mediaSpeedNormalActive: icon {{ "player/speed/audiospeed_menu_1.0", mediaPlayerActiveFg }}; -mediaSpeedMedium: icon {{ "player/speed/audiospeed_menu_1.2", menuIconColor }}; -mediaSpeedMediumActive: icon {{ "player/speed/audiospeed_menu_1.2", mediaPlayerActiveFg }}; -mediaSpeedFast: icon {{ "player/speed/audiospeed_menu_1.5", menuIconColor }}; -mediaSpeedFastActive: icon {{ "player/speed/audiospeed_menu_1.5", mediaPlayerActiveFg }}; -mediaSpeedVeryFast: icon {{ "player/speed/audiospeed_menu_1.7", menuIconColor }}; -mediaSpeedVeryFastActive: icon {{ "player/speed/audiospeed_menu_1.7", mediaPlayerActiveFg }}; -mediaSpeedSuperFast: icon {{ "player/speed/audiospeed_menu_2.0", menuIconColor }}; -mediaSpeedSuperFastActive: icon {{ "player/speed/audiospeed_menu_2.0", mediaPlayerActiveFg }}; mediaPlayerVolumeIcon0: icon { { "player/player_mini_off", mediaPlayerActiveFg }, @@ -292,7 +313,7 @@ mediaPlayerFileLayout: OverviewFileLayout(overviewFileLayout) { mediaPlayerFloatSize: 128px; mediaPlayerFloatMargin: 12px; -mediaPlayerMenuPosition: point(-2px, -2px); +mediaPlayerMenuPosition: point(-2px, -1px); mediaPlayerOrderMenu: Menu(defaultMenu) { itemIconPosition: point(13px, 8px); itemPadding: margins(49px, 9px, 17px, 11px); diff --git a/Telegram/SourceFiles/media/player/media_player_button.cpp b/Telegram/SourceFiles/media/player/media_player_button.cpp index a8e059599..5951443c4 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.cpp +++ b/Telegram/SourceFiles/media/player/media_player_button.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "media/player/media_player_button.h" +#include "ui/effects/ripple_animation.h" #include "ui/painter.h" #include "styles/style_media_player.h" @@ -263,82 +264,73 @@ SpeedButtonLayout::SpeedButtonLayout( float64 speed) : _st(st) , _speed(speed) -, _oldSpeed(speed) -, _nextSpeed(speed) , _metrics(_st.font->f) , _text(SpeedText(speed)) , _textWidth(_metrics.horizontalAdvance(_text)) -, _oldText(_text) -, _oldTextWidth(_textWidth) , _callback(std::move(callback)) { } void SpeedButtonLayout::setSpeed(float64 speed) { speed = base::SafeRound(speed * 10.) / 10.; - if (_nextSpeed == speed) { - return; - } - - _nextSpeed = speed; - if (!_transformProgress.animating()) { - _oldSpeed = _speed; - _oldColor = _lastPaintColor; - _oldText = _text; - _oldTextWidth = _textWidth; - _speed = _nextSpeed; + if (_speed != speed) { + _speed = speed; _text = SpeedText(_speed); _textWidth = _metrics.horizontalAdvance(_text); - _transformBackward = false; - if (_speed != _speed) { - startTransform(0., 1.); - if (_callback) _callback(); - } - } else if (_oldSpeed == _nextSpeed) { - std::swap(_oldSpeed, _speed); - std::swap(_oldColor, _lastPaintColor); - std::swap(_oldText, _text); - std::swap(_oldTextWidth, _textWidth); - startTransform( - _transformBackward ? 0. : 1., - _transformBackward ? 1. : 0.); - _transformBackward = !_transformBackward; + if (_callback) _callback(); } } -void SpeedButtonLayout::finishTransform() { - _transformProgress.stop(); - _transformBackward = false; - if (_callback) _callback(); -} - -void SpeedButtonLayout::paint(QPainter &p, const QColor &color) { - _lastPaintColor = color; - - _st.icon.paint(p, 0, 0, _st.width, color); +void SpeedButtonLayout::paint(QPainter &p, bool over, bool active) { + const auto &color = active ? _st.activeFg : over ? _st.overFg : _st.fg; + const auto inner = QRect(QPoint(), _st.size).marginsRemoved(_st.padding); + _st.icon.paintInCenter(p, inner, color->c); p.setPen(color); p.setFont(_st.font); p.drawText( - QPointF( - (_st.width - _textWidth) / 2., - (_st.height - _metrics.height()) / 2. + _metrics.ascent()), + QPointF(inner.topLeft()) + QPointF( + (inner.width() - _textWidth) / 2., + (inner.height() - _metrics.height()) / 2. + _metrics.ascent()), _text); } -void SpeedButtonLayout::animationCallback() { - if (!_transformProgress.animating()) { - const auto finalSpeed = _nextSpeed; - _nextSpeed = _speed; - setSpeed(finalSpeed); - } - _callback(); +SpeedButton::SpeedButton(QWidget *parent, const style::MediaSpeedButton &st) +: RippleButton(parent, st.ripple) +, _st(st) +, _layout(st, [=] { update(); }, 2.) +, _isDefault(true) { + resize(_st.size); } -void SpeedButtonLayout::startTransform(float64 from, float64 to) { - // No animation for now. - _transformProgress.stop(); - animationCallback(); +void SpeedButton::setSpeed(float64 speed, anim::type animated) { + _isDefault = (speed == 1.); + _layout.setSpeed(speed); + update(); +} + +void SpeedButton::paintEvent(QPaintEvent *e) { + auto p = QPainter(this); + + paintRipple( + p, + QPoint(_st.padding.left(), _st.padding.top()), + _isDefault ? nullptr : &_st.rippleActiveColor->c); + _layout.paint(p, isOver(), !_isDefault); +} + +QPoint SpeedButton::prepareRippleStartPosition() const { + const auto inner = rect().marginsRemoved(_st.padding); + const auto result = mapFromGlobal(QCursor::pos()) - inner.topLeft(); + return inner.contains(result) + ? result + : DisabledRippleStartPosition(); +} + +QImage SpeedButton::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 22e2d6be4..ae2b9563d 100644 --- a/Telegram/SourceFiles/media/player/media_player_button.h +++ b/Telegram/SourceFiles/media/player/media_player_button.h @@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/effects/animations.h" +#include "ui/widgets/buttons.h" #include @@ -60,32 +61,42 @@ public: float64 speed); void setSpeed(float64 speed); - void finishTransform(); - void paint(QPainter &p, const QColor &color); + void paint(QPainter &p, bool over, bool active); private: - void animationCallback(); - void startTransform(float64 from, float64 to); - const style::MediaSpeedButton &_st; float64 _speed = 1.; - float64 _oldSpeed = 1.; - float64 _nextSpeed = 1.; - std::optional _lastPaintColor; - std::optional _oldColor; - Ui::Animations::Simple _transformProgress; - bool _transformBackward = false; QFontMetricsF _metrics; QString _text; float64 _textWidth = 0; - QString _oldText; - float64 _oldTextWidth = 0; Fn _callback; }; +class SpeedButton final : public Ui::RippleButton { +public: + SpeedButton(QWidget *parent, const style::MediaSpeedButton &st); + + [[nodiscard]] const style::MediaSpeedButton &st() const { + return _st; + } + + void setSpeed(float64 speed, anim::type animated = anim::type::normal); + +private: + void paintEvent(QPaintEvent *e) override; + + QPoint prepareRippleStartPosition() const override; + QImage prepareRippleMask() const override; + + const style::MediaSpeedButton &_st; + SpeedButtonLayout _layout; + bool _isDefault = 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 73afd0dcb..f3a6cb7e3 100644 --- a/Telegram/SourceFiles/media/player/media_player_dropdown.cpp +++ b/Telegram/SourceFiles/media/player/media_player_dropdown.cpp @@ -7,24 +7,23 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "media/player/media_player_dropdown.h" +#include "base/invoke_queued.h" #include "base/timer.h" #include "lang/lang_keys.h" +#include "media/player/media_player_button.h" #include "ui/cached_round_corners.h" #include "ui/widgets/menu/menu.h" #include "ui/widgets/menu/menu_action.h" #include "ui/widgets/continuous_sliders.h" +#include "ui/widgets/dropdown_menu.h" #include "ui/widgets/shadow.h" #include "ui/painter.h" #include "styles/style_media_player.h" #include "styles/style_widgets.h" -#include "base/debug_log.h" - namespace Media::Player { namespace { -constexpr auto kSpeedMin = 0.5; -constexpr auto kSpeedMax = 2.5; constexpr auto kSpeedDebounceTimeout = crl::time(1000); [[nodiscard]] float64 SpeedToSliderValue(float64 speed) { @@ -87,12 +86,12 @@ SpeedSliderItem::SpeedSliderItem( not_null parent, const style::MediaSpeedMenu &st, rpl::producer value) -: Ui::Menu::ItemBase(parent, st.menu) +: Ui::Menu::ItemBase(parent, st.dropdown.menu) , _slider(base::make_unique_q(this, st.slider)) , _dummyAction(new QAction(parent)) , _st(st) , _height(st.sliderPadding.top() - + st.menu.itemStyle.font->height + + st.dropdown.menu.itemStyle.font->height + st.sliderPadding.bottom()) , _debounceTimer([=] { _debounced.fire(current()); }) { initResizeHook(parent->sizeValue()); @@ -120,11 +119,11 @@ SpeedSliderItem::SpeedSliderItem( ) | rpl::start_with_next([=](const QRect &clip) { auto p = Painter(this); - p.fillRect(clip, _st.menu.itemBg); + p.fillRect(clip, _st.dropdown.menu.itemBg); const auto left = (_st.sliderPadding.left() - _text.maxWidth()) / 2; - const auto top = _st.menu.itemPadding.top(); - p.setPen(_st.menu.itemFg); + const auto top = _st.dropdown.menu.itemPadding.top(); + p.setPen(_st.dropdown.menu.itemFg); _text.drawLeftElided(p, left, top, _text.maxWidth(), width()); }, lifetime()); @@ -172,6 +171,111 @@ SpeedSliderItem::SpeedSliderItem( }); } +void FillSpeedMenu( + not_null menu, + const style::MediaSpeedMenu &st, + rpl::producer value, + Fn callback) { + auto slider = base::make_unique_q( + menu, + st, + rpl::duplicate(value)); + + slider->debouncedChanges( + ) | rpl::start_with_next(callback, slider->lifetime()); + + struct State { + rpl::variable realtime; + }; + const auto state = slider->lifetime().make_state(); + state->realtime = rpl::single( + slider->current() + ) | rpl::then(rpl::merge( + slider->changing(), + slider->changed() + )); + + menu->addAction(std::move(slider)); + menu->addSeparator(&st.dropdown.menu.separator); + + struct SpeedPoint { + float64 speed = 0.; + tr::phrase<> text; + const style::icon &icon; + const style::icon &iconActive; + }; + const auto points = std::vector{ + { + 0.5, + tr::lng_voice_speed_slow, + st.slow, + st.slowActive }, + { + 1.0, + tr::lng_voice_speed_normal, + st.normal, + st.normalActive }, + { + 1.2, + tr::lng_voice_speed_medium, + st.medium, + st.mediumActive }, + { + 1.5, + tr::lng_voice_speed_fast, + st.fast, + st.fastActive }, + { + 1.7, + tr::lng_voice_speed_very_fast, + st.veryFast, + st.veryFastActive }, + { + 2.0, + tr::lng_voice_speed_super_fast, + st.superFast, + st.superFastActive }, + }; + for (const auto &point : points) { + const auto speed = point.speed; + const auto text = point.text(tr::now); + const auto icon = &point.icon; + const auto iconActive = &point.iconActive; + auto action = base::make_unique_q( + menu, + st.dropdown.menu, + Ui::Menu::CreateAction(menu, text, [=] { callback(speed); }), + &point.icon, + &point.icon); + const auto raw = action.get(); + const auto check = Ui::CreateChild(raw); + const auto skip = st.activeCheckSkip; + check->resize(st.activeCheck.size()); + check->paintRequest( + ) | rpl::start_with_next([check, icon = &st.activeCheck] { + auto p = QPainter(check); + icon->paint(p, 0, 0, check->width()); + }, check->lifetime()); + raw->sizeValue( + ) | rpl::start_with_next([=, skip = st.activeCheckSkip](QSize size) { + check->moveToRight( + skip, + (size.height() - check->height()) / 2, + size.width()); + }, check->lifetime()); + check->setAttribute(Qt::WA_TransparentForMouseEvents); + state->realtime.value( + ) | rpl::start_with_next([=](float64 now) { + const auto chosen = (speed == now); + const auto overriden = chosen ? iconActive : icon; + raw->setIcon(overriden, overriden); + raw->action()->setEnabled(!chosen); + check->setVisible(chosen); + }, raw->lifetime()); + menu->addAction(std::move(action)); + } +} + void SpeedSliderItem::setExternalValue(float64 speed) { if (!_slider->isChanging()) { setSliderValue(speed); @@ -379,109 +483,284 @@ bool Dropdown::eventFilter(QObject *obj, QEvent *e) { return false; } -void FillSpeedMenu( - not_null menu, - const style::MediaSpeedMenu &st, - rpl::producer value, - Fn callback) { - auto slider = base::make_unique_q( - menu, - st, - rpl::duplicate(value)); +WithDropdownController::WithDropdownController( + not_null button, + not_null menuParent, + const style::DropdownMenu &menuSt, + Qt::Alignment menuAlign, + Fn menuOverCallback) +: _button(button) +, _menuParent(menuParent) +, _menuSt(menuSt) +, _menuAlign(menuAlign) +, _menuOverCallback(std::move(menuOverCallback)) { + button->events( + ) | rpl::filter([=](not_null e) { + return (e->type() == QEvent::Enter) + || (e->type() == QEvent::Leave); + }) | rpl::start_with_next([=](not_null e) { + _overButton = (e->type() == QEvent::Enter); + if (_overButton) { + InvokeQueued(button, [=] { + if (_overButton) { + showMenu(); + } + }); + } + }, button->lifetime()); +} - slider->debouncedChanges( - ) | rpl::start_with_next(callback, slider->lifetime()); +not_null WithDropdownController::button() const { + return _button; +} - struct State { - rpl::variable realtime; - }; - const auto state = slider->lifetime().make_state(); - state->realtime = rpl::single( - slider->current() - ) | rpl::then(rpl::merge( - slider->changing(), - slider->changed() - )); +Ui::DropdownMenu *WithDropdownController::menu() const { + return _menu.get(); +} - menu->addAction(std::move(slider)); - menu->addSeparator(&st.menu.separator); +void WithDropdownController::updateDropdownGeometry() { + if (!_menu) { + return; + } + const auto bwidth = _button->width(); + const auto bheight = _button->height(); + const auto mwidth = _menu->width(); + const auto mheight = _menu->height(); + const auto padding = _menuSt.wrap.padding; + const auto x = st::mediaPlayerMenuPosition.x(); + const auto y = st::mediaPlayerMenuPosition.y(); + const auto position = _menu->parentWidget()->mapFromGlobal( + _button->mapToGlobal(QPoint()) + ) + [&] { + switch (_menuAlign) { + case style::al_topleft: return QPoint( + -padding.left() - x, + bheight - padding.top() + y); + case style::al_topright: return QPoint( + bwidth - mwidth + padding.right() + x, + bheight - padding.top() + y); + case style::al_bottomright: return QPoint( + bwidth - mwidth + padding.right() + x, + -mheight + padding.bottom() - y); + case style::al_bottomleft: return QPoint( + -padding.left() - x, + -mheight + padding.bottom() - y); + } + Unexpected("Menu align value."); + }(); + _menu->move(position); +} - struct SpeedPoint { - float64 speed = 0.; - tr::phrase<> text; - const style::icon &icon; - const style::icon &iconActive; - }; - const auto points = std::vector{ - { - 0.5, - tr::lng_voice_speed_slow, - st::mediaSpeedSlow, - st::mediaSpeedSlowActive }, - { - 1.0, - tr::lng_voice_speed_normal, - st::mediaSpeedNormal, - st::mediaSpeedNormalActive }, - { - 1.2, - tr::lng_voice_speed_medium, - st::mediaSpeedMedium, - st::mediaSpeedMediumActive }, - { - 1.5, - tr::lng_voice_speed_fast, - st::mediaSpeedFast, - st::mediaSpeedFastActive }, - { - 1.7, - tr::lng_voice_speed_very_fast, - st::mediaSpeedVeryFast, - st::mediaSpeedVeryFastActive }, - { - 2.0, - tr::lng_voice_speed_super_fast, - st::mediaSpeedSuperFast, - st::mediaSpeedSuperFastActive }, - }; - for (const auto &point : points) { - const auto speed = point.speed; - const auto text = point.text(tr::now); - const auto icon = &point.icon; - const auto iconActive = &point.iconActive; - auto action = base::make_unique_q( - menu, - st::mediaSpeedMenu.menu, - Ui::Menu::CreateAction(menu, text, [=] { callback(speed); }), - &point.icon, - &point.icon); - const auto raw = action.get(); - const auto check = Ui::CreateChild(raw); - const auto skip = st.activeCheckSkip; - check->resize(st.activeCheck.size()); - check->paintRequest( - ) | rpl::start_with_next([check, icon = &st.activeCheck] { - auto p = QPainter(check); - icon->paint(p, 0, 0, check->width()); - }, check->lifetime()); - raw->sizeValue( - ) | rpl::start_with_next([=, skip = st.activeCheckSkip](QSize size) { - check->moveToRight( - skip, - (size.height() - check->height()) / 2, - size.width()); - }, check->lifetime()); - check->setAttribute(Qt::WA_TransparentForMouseEvents); - state->realtime.value( - ) | rpl::start_with_next([=](float64 now) { - const auto chosen = (speed == now); - const auto overriden = chosen ? iconActive : icon; - raw->setIcon(overriden, overriden); - raw->action()->setEnabled(!chosen); - check->setVisible(chosen); - }, raw->lifetime()); - menu->addAction(std::move(action)); +void WithDropdownController::hideTemporarily() { + if (_menu && !_menu->isHidden()) { + _temporarilyHidden = true; + _menu->hide(); } } +void WithDropdownController::showBack() { + if (_temporarilyHidden) { + _temporarilyHidden = false; + if (_menu && _menu->isHidden()) { + _menu->show(); + } + } +} + +void WithDropdownController::showMenu() { + if (_menu) { + return; + } + _menu.emplace(_menuParent, _menuSt); + const auto raw = _menu.get(); + _menu->events( + ) | rpl::start_with_next([this](not_null e) { + const auto type = e->type(); + if (type == QEvent::Enter) { + _menuOverCallback(true); + } else if (type == QEvent::Leave) { + _menuOverCallback(false); + } + }, _menu->lifetime()); + _menu->setHiddenCallback([=]{ + Ui::PostponeCall(raw, [this] { + _menu = nullptr; + }); + }); + _button->installEventFilter(raw); + fillMenu(raw); + updateDropdownGeometry(); + const auto origin = [&] { + using Origin = Ui::PanelAnimation::Origin; + switch (_menuAlign) { + case style::al_topleft: return Origin::TopLeft; + case style::al_topright: return Origin::TopRight; + case style::al_bottomright: return Origin::BottomRight; + case style::al_bottomleft: return Origin::BottomLeft; + } + Unexpected("Menu align value."); + }(); + _menu->showAnimated(origin); +} + +OrderController::OrderController( + not_null button, + not_null menuParent, + Fn menuOverCallback, + rpl::producer value, + Fn change) +: WithDropdownController( + button, + menuParent, + st::mediaPlayerMenu, + style::al_topright, + std::move(menuOverCallback)) +, _button(button) +, _appOrder(std::move(value)) +, _change(std::move(change)) { + button->setClickedCallback([=] { + showMenu(); + }); + + _appOrder.value( + ) | rpl::start_with_next([=] { + updateIcon(); + }, button->lifetime()); +} + +void OrderController::fillMenu(not_null menu) { + const auto addOrderAction = [&](OrderMode mode) { + struct Fields { + QString label; + const style::icon &icon; + const style::icon &activeIcon; + }; + const auto active = (_appOrder.current() == mode); + const auto callback = [change = _change, mode, active] { + change(active ? OrderMode::Default : mode); + }; + const auto fields = [&]() -> Fields { + switch (mode) { + case OrderMode::Reverse: return { + .label = tr::lng_audio_player_reverse(tr::now), + .icon = st::mediaPlayerOrderIconReverse, + .activeIcon = st::mediaPlayerOrderIconReverseActive, + }; + case OrderMode::Shuffle: return { + .label = tr::lng_audio_player_shuffle(tr::now), + .icon = st::mediaPlayerOrderIconShuffle, + .activeIcon = st::mediaPlayerOrderIconShuffleActive, + }; + } + Unexpected("Order mode in addOrderAction."); + }(); + menu->addAction(base::make_unique_q( + menu, + (active + ? st::mediaPlayerOrderMenuActive + : st::mediaPlayerOrderMenu), + Ui::Menu::CreateAction(menu, fields.label, callback), + &(active ? fields.activeIcon : fields.icon), + &(active ? fields.activeIcon : fields.icon))); + }; + addOrderAction(OrderMode::Reverse); + addOrderAction(OrderMode::Shuffle); +} + +void OrderController::updateIcon() { + switch (_appOrder.current()) { + case OrderMode::Default: + _button->setIconOverride( + &st::mediaPlayerReverseDisabledIcon, + &st::mediaPlayerReverseDisabledIconOver); + _button->setRippleColorOverride( + &st::mediaPlayerRepeatDisabledRippleBg); + break; + case OrderMode::Reverse: + _button->setIconOverride(&st::mediaPlayerReverseIcon); + _button->setRippleColorOverride(nullptr); + break; + case OrderMode::Shuffle: + _button->setIconOverride(&st::mediaPlayerShuffleIcon); + _button->setRippleColorOverride(nullptr); + break; + } +} + +SpeedController::SpeedController( + not_null button, + not_null menuParent, + Fn menuOverCallback, + Fn value, + Fn change) +: WithDropdownController( + button, + menuParent, + button->st().menu.dropdown, + button->st().menuAlign, + std::move(menuOverCallback)) +, _st(button->st()) +, _lookup(std::move(value)) +, _change(std::move(change)) { + button->setClickedCallback([=] { + toggleDefault(); + save(); + if (const auto current = menu()) { + current->otherEnter(); + } + }); + + 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(); +} + +float64 SpeedController::speed() const { + return _isDefault ? 1. : _speed; +} + +bool SpeedController::isDefault() const { + return _isDefault; +} + +float64 SpeedController::lastNonDefaultSpeed() const { + return _speed; +} + +void SpeedController::toggleDefault() { + _isDefault = !_isDefault; + _speedChanged.fire(speed()); +} + +void SpeedController::setSpeed(float64 newSpeed) { + if (!(_isDefault = (newSpeed == 1.))) { + _speed = newSpeed; + } + _speedChanged.fire(speed()); +} + +void SpeedController::save() { + _change(speed()); + _saved.fire({}); +} + +void SpeedController::fillMenu(not_null menu) { + FillSpeedMenu( + menu->menu(), + _st.menu, + _speedChanged.events_starting_with(speed()), + [=](float64 speed) { setSpeed(speed); save(); }); +} + } // namespace Media::Player diff --git a/Telegram/SourceFiles/media/player/media_player_dropdown.h b/Telegram/SourceFiles/media/player/media_player_dropdown.h index 627c276aa..63197dbb8 100644 --- a/Telegram/SourceFiles/media/player/media_player_dropdown.h +++ b/Telegram/SourceFiles/media/player/media_player_dropdown.h @@ -7,20 +7,31 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #pragma once +#include "base/timer.h" +#include "media/media_common.h" #include "ui/rp_widget.h" #include "ui/effects/animations.h" -#include "base/timer.h" namespace style { struct MediaSpeedMenu; +struct MediaSpeedButton; +struct DropdownMenu; } // namespace style +namespace Ui { +class DropdownMenu; +class AbstractButton; +class IconButton; +} // namespace Ui + namespace Ui::Menu { class Menu; } // namespace Ui::Menu namespace Media::Player { +class SpeedButton; + class Dropdown final : public Ui::RpWidget { public: explicit Dropdown(QWidget *parent); @@ -57,10 +68,89 @@ private: }; -void FillSpeedMenu( - not_null menu, - const style::MediaSpeedMenu &st, - rpl::producer value, - Fn callback); +class WithDropdownController { +public: + WithDropdownController( + not_null button, + not_null menuParent, + const style::DropdownMenu &menuSt, + Qt::Alignment menuAlign, + Fn menuOverCallback); + virtual ~WithDropdownController() = default; + + [[nodiscard]] not_null button() const; + Ui::DropdownMenu *menu() const; + + void updateDropdownGeometry(); + + void hideTemporarily(); + void showBack(); + +protected: + void showMenu(); + +private: + virtual void fillMenu(not_null menu) = 0; + + const not_null _button; + const not_null _menuParent; + const style::DropdownMenu &_menuSt; + const Qt::Alignment _menuAlign = Qt::AlignTop | Qt::AlignRight; + const Fn _menuOverCallback; + base::unique_qptr _menu; + bool _temporarilyHidden = false; + bool _overButton = false; + +}; + +class OrderController final : public WithDropdownController { +public: + OrderController( + not_null button, + not_null menuParent, + Fn menuOverCallback, + rpl::producer value, + Fn change); + +private: + void fillMenu(not_null menu) override; + void updateIcon(); + + const not_null _button; + rpl::variable _appOrder; + Fn _change; + +}; + +class SpeedController final : public WithDropdownController { +public: + SpeedController( + not_null button, + not_null menuParent, + Fn menuOverCallback, + Fn value, + Fn change); + + [[nodiscard]] rpl::producer<> saved() const; + +private: + void fillMenu(not_null menu) override; + + [[nodiscard]] float64 speed() const; + [[nodiscard]] bool isDefault() const; + [[nodiscard]] float64 lastNonDefaultSpeed() const; + void toggleDefault(); + void setSpeed(float64 newSpeed); + void save(); + + const style::MediaSpeedButton &_st; + Fn _lookup; + Fn _change; + float64 _speed = kSpedUpDefault; + bool _isDefault = true; + rpl::event_stream _speedChanged; + rpl::event_stream<> _saved; + +}; } // namespace Media::Player diff --git a/Telegram/SourceFiles/media/player/media_player_instance.cpp b/Telegram/SourceFiles/media/player/media_player_instance.cpp index 0fe06ffbb..5e1655cc0 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.cpp +++ b/Telegram/SourceFiles/media/player/media_player_instance.cpp @@ -52,13 +52,6 @@ constexpr auto kRememberShuffledOrderItems = 16; constexpr auto kMinLengthForSavePosition = 20 * TimeId(60); // 20 minutes. -auto VoicePlaybackSpeed() { - return std::clamp( - Core::App().settings().voicePlaybackSpeed(), - Media::Audio::kSpeedMin, - Media::Audio::kSpeedMax); -} - base::options::toggle OptionDisableAutoplayNext({ .id = kOptionDisableAutoplayNext, .name = "Disable auto-play of the next track", @@ -847,7 +840,7 @@ Streaming::PlaybackOptions Instance::streamingOptions( ? Streaming::Mode::Both : Streaming::Mode::Audio; result.speed = audioId.changeablePlaybackSpeed() - ? VoicePlaybackSpeed() + ? Core::App().settings().voicePlaybackSpeed() : 1.; result.audioId = audioId; if (position >= 0) { @@ -1143,7 +1136,8 @@ void Instance::updateVoicePlaybackSpeed() { return; } if (const auto streamed = data->streamed.get()) { - streamed->instance.setSpeed(VoicePlaybackSpeed()); + streamed->instance.setSpeed( + Core::App().settings().voicePlaybackSpeed()); } } } diff --git a/Telegram/SourceFiles/media/player/media_player_instance.h b/Telegram/SourceFiles/media/player/media_player_instance.h index f6879e55f..fce26855b 100644 --- a/Telegram/SourceFiles/media/player/media_player_instance.h +++ b/Telegram/SourceFiles/media/player/media_player_instance.h @@ -14,6 +14,11 @@ class AudioMsgId; class DocumentData; class History; +namespace Media { +enum class RepeatMode; +enum class OrderMode; +} // namespace Media + namespace Media { namespace Audio { class Instance; @@ -45,18 +50,6 @@ namespace Player { extern const char kOptionDisableAutoplayNext[]; -enum class RepeatMode { - None, - One, - All, -}; - -enum class OrderMode { - Default, - Reverse, - Shuffle, -}; - class Instance; struct TrackState; diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp index 4c75dfebf..0d375b603 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.cpp +++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp @@ -42,383 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Media { namespace Player { -class WithDropdownController { -public: - WithDropdownController( - not_null button, - not_null menuParent, - Fn menuOverCallback); - virtual ~WithDropdownController() = default; - - [[nodiscard]] not_null button() const; - Ui::DropdownMenu *menu() const; - - void updateDropdownGeometry(); - - void hideTemporarily(); - void showBack(); - -protected: - void showMenu(); - -private: - virtual void fillMenu(not_null menu) = 0; - - const not_null _button; - const not_null _menuParent; - const Fn _menuOverCallback; - base::unique_qptr _menu; - bool _temporarilyHidden = false; - bool _overButton = false; - -}; - -class Widget::SpeedButton final : public Ui::RippleButton { -public: - SpeedButton(QWidget *parent); - - void setSpeed(float64 speed, anim::type animated = anim::type::normal); - -private: - void paintEvent(QPaintEvent *e) override; - - QPoint prepareRippleStartPosition() const override; - QImage prepareRippleMask() const override; - - SpeedButtonLayout _layout; - QPoint _layoutPosition; - bool _isDefault = false; - -}; - -class Widget::OrderController final : public WithDropdownController { -public: - OrderController( - not_null button, - not_null menuParent, - Fn menuOverCallback); - -private: - void fillMenu(not_null menu) override; - void updateIcon(); - - const not_null _button; - -}; - -class Widget::SpeedController final : public WithDropdownController { -public: - SpeedController( - not_null button, - not_null menuParent, - Fn menuOverCallback); - - [[nodiscard]] rpl::producer<> saved() const; - -private: - void fillMenu(not_null menu) override; - - [[nodiscard]] float64 speed() const; - [[nodiscard]] bool isDefault() const; - [[nodiscard]] float64 lastNonDefaultSpeed() const; - void toggleDefault(); - void setSpeed(float64 newSpeed); - void save(); - - float64 _speed = 1.7; - bool _isDefault = true; - rpl::event_stream _speedChanged; - rpl::event_stream<> _saved; - -}; - -WithDropdownController::WithDropdownController( - not_null button, - not_null menuParent, - Fn menuOverCallback) -: _button(button) -, _menuParent(menuParent) -, _menuOverCallback(std::move(menuOverCallback)) { - button->events( - ) | rpl::filter([=](not_null e) { - return (e->type() == QEvent::Enter) - || (e->type() == QEvent::Leave); - }) | rpl::start_with_next([=](not_null e) { - _overButton = (e->type() == QEvent::Enter); - if (_overButton) { - InvokeQueued(button, [=] { - if (_overButton) { - showMenu(); - } - }); - } - }, button->lifetime()); -} - -not_null WithDropdownController::button() const { - return _button; -} - -Ui::DropdownMenu *WithDropdownController::menu() const { - return _menu.get(); -} - -void WithDropdownController::updateDropdownGeometry() { - if (!_menu) { - return; - } - const auto position = _menu->parentWidget()->mapFromGlobal( - _button->mapToGlobal( - QPoint(_button->width(), _button->height()))); - const auto padding = st::mediaPlayerMenu.wrap.padding; - _menu->move(position - - QPoint(_menu->width(), 0) - + QPoint(padding.right(), -padding.top()) - + st::mediaPlayerMenuPosition); -} - -void WithDropdownController::hideTemporarily() { - if (_menu && !_menu->isHidden()) { - _temporarilyHidden = true; - _menu->hide(); - } -} - -void WithDropdownController::showBack() { - if (_temporarilyHidden) { - _temporarilyHidden = false; - if (_menu && _menu->isHidden()) { - _menu->show(); - } - } -} - -void WithDropdownController::showMenu() { - if (_menu) { - return; - } - _menu.emplace(_menuParent, st::mediaPlayerMenu); - const auto raw = _menu.get(); - _menu->events( - ) | rpl::start_with_next([this](not_null e) { - const auto type = e->type(); - if (type == QEvent::Enter) { - _menuOverCallback(true); - } else if (type == QEvent::Leave) { - _menuOverCallback(false); - } - }, _menu->lifetime()); - _menu->setHiddenCallback([=]{ - Ui::PostponeCall(raw, [this] { - _menu = nullptr; - }); - }); - _button->installEventFilter(raw); - fillMenu(raw); - updateDropdownGeometry(); - _menu->showAnimated(Ui::PanelAnimation::Origin::TopRight); -} - -Widget::SpeedButton::SpeedButton(QWidget *parent) -: RippleButton(parent, st::mediaPlayerSpeedRipple) -, _layout(st::mediaSpeedButton, [=] { update(); }, 2.) -, _isDefault(true) { - resize(st::mediaPlayerSpeedSize); - _layoutPosition = QPoint( - (st::mediaPlayerSpeedSize.width() - st::mediaSpeedButton.width) / 2, - st::mediaPlayerSpeedSize.height() - st::mediaSpeedButton.height); -} - -void Widget::SpeedButton::setSpeed(float64 speed, anim::type animated) { - _isDefault = (speed == 1.); - _layout.setSpeed(speed); - if (animated == anim::type::instant) { - _layout.finishTransform(); - } - update(); -} - -void Widget::SpeedButton::paintEvent(QPaintEvent *e) { - auto p = QPainter(this); - - const auto innerHeight = st::mediaSpeedButton.icon.height(); - paintRipple( - p, - QPoint(0, height() - innerHeight), - _isDefault ? &st::mediaPlayerSpeedDisabledRippleBg->c : nullptr); - - const auto &color = !_isDefault - ? st::mediaPlayerActiveFg - : isOver() - ? st::menuIconFgOver - : st::menuIconFg; - p.translate(_layoutPosition); - _layout.paint(p, color->c); -} - -QPoint Widget::SpeedButton::prepareRippleStartPosition() const { - const auto innerHeight = st::mediaSpeedButton.icon.height(); - const auto result = mapFromGlobal(QCursor::pos()) - - QPoint(0, height() - innerHeight); - const auto rect = QRect(0, 0, width(), innerHeight); - return rect.contains(result) - ? result - : DisabledRippleStartPosition(); -} - -QImage Widget::SpeedButton::prepareRippleMask() const { - const auto innerHeight = st::mediaSpeedButton.icon.height(); - return Ui::RippleAnimation::RoundRectMask( - { width(), innerHeight }, - st::mediaPlayerSpeedRadius); -} - -Widget::OrderController::OrderController( - not_null button, - not_null menuParent, - Fn menuOverCallback) -: WithDropdownController(button, menuParent, std::move(menuOverCallback)) -, _button(button) { - button->setClickedCallback([=] { - showMenu(); - }); - - Core::App().settings().playerOrderModeValue( - ) | rpl::start_with_next([=] { - updateIcon(); - }, button->lifetime()); -} - -void Widget::OrderController::fillMenu(not_null menu) { - const auto addOrderAction = [&](OrderMode mode) { - struct Fields { - QString label; - const style::icon &icon; - const style::icon &activeIcon; - }; - const auto current = Core::App().settings().playerOrderMode(); - const auto active = (current == mode); - const auto callback = [=] { - Core::App().settings().setPlayerOrderMode(active - ? OrderMode::Default - : mode); - Core::App().saveSettingsDelayed(); - }; - const auto fields = [&]() -> Fields { - switch (mode) { - case OrderMode::Reverse: return { - .label = tr::lng_audio_player_reverse(tr::now), - .icon = st::mediaPlayerOrderIconReverse, - .activeIcon = st::mediaPlayerOrderIconReverseActive, - }; - case OrderMode::Shuffle: return { - .label = tr::lng_audio_player_shuffle(tr::now), - .icon = st::mediaPlayerOrderIconShuffle, - .activeIcon = st::mediaPlayerOrderIconShuffleActive, - }; - } - Unexpected("Order mode in addOrderAction."); - }(); - menu->addAction(base::make_unique_q( - menu, - (active - ? st::mediaPlayerOrderMenuActive - : st::mediaPlayerOrderMenu), - Ui::Menu::CreateAction(menu, fields.label, callback), - &(active ? fields.activeIcon : fields.icon), - &(active ? fields.activeIcon : fields.icon))); - }; - addOrderAction(OrderMode::Reverse); - addOrderAction(OrderMode::Shuffle); -} - -void Widget::OrderController::updateIcon() { - switch (Core::App().settings().playerOrderMode()) { - case OrderMode::Default: - _button->setIconOverride( - &st::mediaPlayerReverseDisabledIcon, - &st::mediaPlayerReverseDisabledIconOver); - _button->setRippleColorOverride( - &st::mediaPlayerRepeatDisabledRippleBg); - break; - case OrderMode::Reverse: - _button->setIconOverride(&st::mediaPlayerReverseIcon); - _button->setRippleColorOverride(nullptr); - break; - case OrderMode::Shuffle: - _button->setIconOverride(&st::mediaPlayerShuffleIcon); - _button->setRippleColorOverride(nullptr); - break; - } -} - -Widget::SpeedController::SpeedController( - not_null button, - not_null menuParent, - Fn menuOverCallback) -: WithDropdownController(button, menuParent, std::move(menuOverCallback)) { - button->setClickedCallback([=] { - toggleDefault(); - save(); - if (const auto current = menu()) { - current->otherEnter(); - } - }); - - setSpeed(Core::App().settings().voicePlaybackSpeed()); - _speed = Core::App().settings().voicePlaybackSpeed(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<> Widget::SpeedController::saved() const { - return _saved.events(); -} - -float64 Widget::SpeedController::speed() const { - return _isDefault ? 1. : _speed; -} - -bool Widget::SpeedController::isDefault() const { - return _isDefault; -} - -float64 Widget::SpeedController::lastNonDefaultSpeed() const { - return _speed; -} - -void Widget::SpeedController::toggleDefault() { - _isDefault = !_isDefault; - _speedChanged.fire(speed()); -} - -void Widget::SpeedController::setSpeed(float64 newSpeed) { - if (!(_isDefault = (newSpeed == 1.))) { - _speed = newSpeed; - } - _speedChanged.fire(speed()); -} - -void Widget::SpeedController::save() { - Core::App().settings().setVoicePlaybackSpeed(speed()); - Core::App().saveSettingsDelayed(); - _saved.fire({}); -} - -void Widget::SpeedController::fillMenu(not_null menu) { - FillSpeedMenu( - menu->menu(), - st::mediaSpeedMenu, - _speedChanged.events_starting_with(speed()), - [=](float64 speed) { setSpeed(speed); save(); }); -} - Widget::Widget( QWidget *parent, not_null dropdownsParent, @@ -433,7 +56,7 @@ Widget::Widget( , _volumeToggle(rightControls(), st::mediaPlayerVolumeToggle) , _repeatToggle(rightControls(), st::mediaPlayerRepeatButton) , _orderToggle(rightControls(), st::mediaPlayerRepeatButton) -, _speedToggle(rightControls()) +, _speedToggle(rightControls(), st::mediaPlayerSpeedButton) , _close(this, st::mediaPlayerClose) , _shadow(this) , _playbackSlider(this, st::mediaPlayerPlayback) @@ -443,12 +66,16 @@ Widget::Widget( std::make_unique( _orderToggle.data(), dropdownsParent, - [=](bool over) { markOver(over); })) + [=](bool over) { markOver(over); }, + Core::App().settings().playerOrderModeValue(), + [=](OrderMode value) { saveOrder(value); })) , _speedController( std::make_unique( _speedToggle.data(), dropdownsParent, - [=](bool over) { markOver(over); })) { + [=](bool over) { markOver(over); }, + [=](bool lastNonDefault) { return speedLookup(lastNonDefault); }, + [=](float64 speed) { saveSpeed(speed); })) { setAttribute(Qt::WA_OpaquePaintEvent); setMouseTracking(true); resize(width(), st::mediaPlayerHeight + st::lineWidth); @@ -789,6 +416,20 @@ void Widget::markOver(bool over) { } } +void Widget::saveOrder(OrderMode mode) { + Core::App().settings().setPlayerOrderMode(mode); + Core::App().saveSettingsDelayed(); +} + +float64 Widget::speedLookup(bool lastNonDefault) const { + return Core::App().settings().voicePlaybackSpeed(lastNonDefault); +} + +void Widget::saveSpeed(float64 speed) { + Core::App().settings().setVoicePlaybackSpeed(speed); + Core::App().saveSettingsDelayed(); +} + void Widget::mouseMoveEvent(QMouseEvent *e) { updateOverLabelsState(e->pos()); } diff --git a/Telegram/SourceFiles/media/player/media_player_widget.h b/Telegram/SourceFiles/media/player/media_player_widget.h index e38e8ecc6..65c179d9e 100644 --- a/Telegram/SourceFiles/media/player/media_player_widget.h +++ b/Telegram/SourceFiles/media/player/media_player_widget.h @@ -23,6 +23,10 @@ template class FadeWrap; } // namespace Ui +namespace Media { +enum class OrderMode; +} // namespace Media + namespace Media::View { class PlaybackProgress; } // namespace Media::View @@ -34,6 +38,9 @@ class SessionController; namespace Media::Player { class Dropdown; +class SpeedButton; +class OrderController; +class SpeedController; struct TrackState; class Widget final : public Ui::RpWidget { @@ -103,6 +110,10 @@ private: void updateTimeLabel(); void markOver(bool over); + void saveOrder(OrderMode mode); + [[nodiscard]] float64 speedLookup(bool lastNonDefault) const; + void saveSpeed(float64 speed); + const not_null _controller; const not_null _orderMenuParent; @@ -128,9 +139,6 @@ private: bool _wontBeOver = false; bool _volumeHidden = false; - class SpeedButton; - class OrderController; - class SpeedController; object_ptr _nameLabel; object_ptr> _rightControls; object_ptr _timeLabel; diff --git a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp index a5293cfea..e2ca66cc1 100644 --- a/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp +++ b/Telegram/SourceFiles/media/streaming/media_streaming_player.cpp @@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/streaming/media_streaming_audio_track.h" #include "media/streaming/media_streaming_video_track.h" #include "media/audio/media_audio.h" // for SupportsSpeedControl() +#include "media/media_common.h" #include "data/data_document.h" // for DocumentData::duration() namespace Media { @@ -528,8 +529,7 @@ void Player::fail(Error error) { } void Player::play(const PlaybackOptions &options) { - Expects(options.speed >= Audio::kSpeedMin - && options.speed <= Audio::kSpeedMax); + Expects(options.speed >= kSpeedMin && options.speed <= kSpeedMax); // Looping video with audio is not supported for now. Expects(!options.loop || (options.mode != Mode::Both)); @@ -829,7 +829,7 @@ float64 Player::speed() const { } void Player::setSpeed(float64 speed) { - Expects(speed >= Audio::kSpeedMin && speed <= Audio::kSpeedMax); + Expects(speed >= kSpeedMin && speed <= kSpeedMax); if (!Media::Audio::SupportsSpeedControl()) { speed = 1.; diff --git a/Telegram/SourceFiles/media/system_media_controls_manager.cpp b/Telegram/SourceFiles/media/system_media_controls_manager.cpp index a09ad828f..fc6105ab3 100644 --- a/Telegram/SourceFiles/media/system_media_controls_manager.cpp +++ b/Telegram/SourceFiles/media/system_media_controls_manager.cpp @@ -26,8 +26,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Media { namespace { -[[nodiscard]] auto RepeatModeToLoopStatus(Media::Player::RepeatMode mode) { - using Mode = Media::Player::RepeatMode; +[[nodiscard]] auto RepeatModeToLoopStatus(Media::RepeatMode mode) { + using Mode = Media::RepeatMode; using Status = base::Platform::SystemMediaControls::LoopStatus; switch (mode) { case Mode::None: return Status::None; @@ -199,8 +199,8 @@ SystemMediaControlsManager::SystemMediaControlsManager() _controls->setIsPreviousEnabled(mediaPlayer->previousAvailable(type)); }, _lifetime); - using Media::Player::RepeatMode; - using Media::Player::OrderMode; + using Media::RepeatMode; + using Media::OrderMode; Core::App().settings().playerRepeatModeValue( ) | rpl::start_with_next([=](RepeatMode mode) { diff --git a/Telegram/SourceFiles/media/system_media_controls_manager.h b/Telegram/SourceFiles/media/system_media_controls_manager.h index 7b56d21a9..f7740771e 100644 --- a/Telegram/SourceFiles/media/system_media_controls_manager.h +++ b/Telegram/SourceFiles/media/system_media_controls_manager.h @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_audio_msg_id.h" #include "media/player/media_player_instance.h" +#include "media/media_common.h" namespace base::Platform { class SystemMediaControls; @@ -39,9 +40,9 @@ private: const std::unique_ptr _controls; std::vector> _cachedMediaView; - std::unique_ptr _streamed; + std::unique_ptr _streamed; AudioMsgId _lastAudioMsgId; - Media::Player::OrderMode _lastOrderMode; + OrderMode _lastOrderMode = OrderMode::Default; rpl::lifetime _lifetimeDownload; rpl::lifetime _lifetime; diff --git a/Telegram/SourceFiles/media/view/media_view.style b/Telegram/SourceFiles/media/view/media_view.style index 7c8b88e0d..d2b3decf5 100644 --- a/Telegram/SourceFiles/media/view/media_view.style +++ b/Telegram/SourceFiles/media/view/media_view.style @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL using "ui/basic.style"; using "ui/widgets/widgets.style"; using "ui/menu_icons.style"; +using "media/player/media_player.style"; mediaviewOverDuration: 150; @@ -24,7 +25,8 @@ mediaviewPlayback: MediaSlider { seekSize: size(12px, 12px); duration: mediaviewOverDuration; } -mediaviewPlaybackTop: 52px; +mediaviewPlaybackTop: 49px; +mediaviewPlayProgressTop: 46px; mediaviewControlsButton: IconButton { ripple: RippleAnimation(defaultRippleAnimation) { @@ -34,46 +36,41 @@ mediaviewControlsButton: IconButton { duration: mediaviewOverDuration; } -mediaviewControllerSize: size(481px, 75px); +mediaviewControllerSize: size(480px, 72px); mediaviewPlayProgressLabel: LabelSimple(defaultLabelSimple) { - font: semiboldFont; + font: font(12px semibold); textFg: mediaviewPlaybackProgressFg; } -mediaviewPlayProgressSkip: 8px; -mediaviewPlayProgressLeft: 8px; -mediaviewPlayButtonTop: 5px; +mediaviewPlayProgressSkip: 10px; +mediaviewPlayProgressLeft: 4px; +mediaviewPlayButtonTop: 2px; mediaviewPlayButton: IconButton(mediaviewControlsButton) { - width: 42px; - height: 42px; - rippleAreaSize: 42px; + width: 40px; + height: 40px; + rippleAreaSize: 40px; icon: icon {{ "player/player_play", mediaviewPlaybackIconFg }}; iconOver: icon {{ "player/player_play", mediaviewPlaybackIconFgOver }}; - iconPosition: point(9px, 9px); + iconPosition: point(8px, 8px); } mediaviewPauseIcon: icon {{ "player/player_pause", mediaviewPlaybackIconFg }}; mediaviewPauseIconOver: icon {{ "player/player_pause", mediaviewPlaybackIconFgOver }}; -mediaviewButtonsTop: 7px; +mediaviewButtonsTop: 6px; +mediaviewButtonsRight: 8px; -mediaviewMenuToggleSkip: 4px; -mediaviewMenuToggle: IconButton(mediaviewControlsButton) { - width: 34px; - height: 34px; - rippleAreaSize: 34px; - icon: icon {{ "player/player_more", mediaviewPlaybackIconFg }}; - iconOver: icon {{ "player/player_more", mediaviewPlaybackIconFgOver }}; - iconPosition: point(5px, 5px); -} - -mediaviewPipButtonSkip: 5px; -mediaviewPipButton: IconButton(mediaviewMenuToggle) { +mediaviewPipButtonSkip: 4px; +mediaviewPipButton: IconButton(mediaviewControlsButton) { + width: 32px; + height: 32px; + rippleAreaSize: 32px; icon: icon {{ "player/player_pip", mediaviewPlaybackIconFg }}; iconOver: icon {{ "player/player_pip", mediaviewPlaybackIconFgOver }}; + iconPosition: point(4px, 4px); } -mediaviewFullScreenButtonSkip: 8px; -mediaviewFullScreenButton: IconButton(mediaviewMenuToggle) { +mediaviewFullScreenButtonSkip: 4px; +mediaviewFullScreenButton: IconButton(mediaviewPipButton) { icon: icon {{ "player/player_fullscreen", mediaviewPlaybackIconFg }}; iconOver: icon {{ "player/player_fullscreen", mediaviewPlaybackIconFgOver }}; } @@ -89,17 +86,17 @@ mediaviewVolumeIcon1: icon {{ "player/player_volume_small", mediaviewPlaybackIco mediaviewVolumeIcon1Over: icon {{ "player/player_volume_small", mediaviewPlaybackIconFgOver }}; mediaviewVolumeIcon2: icon {{ "player/player_volume_on", mediaviewPlaybackIconFg }}; mediaviewVolumeIcon2Over: icon {{ "player/player_volume_on", mediaviewPlaybackIconFgOver }}; -mediaviewVolumeTop: 10px; -mediaviewVolumeToggleSkip: 11px; +mediaviewVolumeTop: 6px; +mediaviewVolumeToggleLeft: 6px; mediaviewVolumeToggle: IconButton(mediaviewControlsButton) { - width: 30px; - height: 30px; - rippleAreaSize: 30px; + width: 32px; + height: 32px; + rippleAreaSize: 32px; icon: mediaviewVolumeIcon0; iconOver: mediaviewVolumeIcon0Over; - iconPosition: point(3px, 3px); + iconPosition: point(4px, 4px); } -mediaviewVolumeSkip: 4px; +mediaviewVolumeSkip: 3px; mediaviewLeft: icon { { "mediaview/next_shadow-flip_horizontal", windowShadowFg } @@ -143,6 +140,9 @@ mediaviewFileIconSize: 80px; mediaviewFileLink: defaultLinkButton; +mediaviewMenuSeparator: MenuSeparator(defaultMenuSeparator) { + fg: mediaviewMenuFg; +} mediaviewMenu: Menu(menuWithIcons) { itemBg: mediaviewMenuBg; itemBgOver: mediaviewMenuBgOver; @@ -153,9 +153,7 @@ mediaviewMenu: Menu(menuWithIcons) { itemFgShortcutOver: mediaviewMenuFg; itemFgShortcutDisabled: mediaviewMenuFg; - separator: MenuSeparator(defaultMenuSeparator) { - fg: mediaviewMenuFg; - } + separator: mediaviewMenuSeparator; ripple: RippleAnimation(defaultRippleAnimation) { color: mediaviewMenuBgRipple; @@ -183,39 +181,6 @@ mediaviewDropdownMenu: DropdownMenu(defaultDropdownMenu) { } } -mediaviewControlsMenu: Menu(defaultMenu) { - itemBg: mediaviewSaveMsgBg; - itemBgOver: mediaviewPlaybackIconRipple; - itemFg: mediaviewPlaybackProgressFg; - itemFgOver: mediaviewPlaybackProgressFg; - itemFgDisabled: mediaviewPlaybackProgressFg; - itemFgShortcut: mediaviewPlaybackProgressFg; - itemFgShortcutOver: mediaviewPlaybackProgressFg; - itemFgShortcutDisabled: mediaviewPlaybackProgressFg; - - separator: MenuSeparator(defaultMenuSeparator) { - fg: mediaviewPlaybackIconRipple; - } - - arrow: icon {{ "menu/submenu_arrow", mediaviewPlaybackProgressFg }}; - - ripple: RippleAnimation(defaultRippleAnimation) { - color: mediaviewPlaybackIconRipple; - } -} -mediaviewControlsMenuShadow: Shadow(defaultEmptyShadow) { - fallback: mediaviewSaveMsgBg; -} -mediaviewControlsPanelAnimation: PanelAnimation(defaultPanelAnimation) { - fadeBg: mediaviewSaveMsgBg; - shadow: mediaviewControlsMenuShadow; -} -mediaviewControlsPopupMenu: PopupMenu(defaultPopupMenu) { - shadow: mediaviewControlsMenuShadow; - menu: mediaviewControlsMenu; - animation: mediaviewControlsPanelAnimation; -} - mediaviewSaveMsgCheck: icon {{ "mediaview/save_check", mediaviewSaveMsgFg }}; mediaviewSaveMsgPadding: margins(55px, 19px, 29px, 20px); mediaviewSaveMsgCheckPos: point(23px, 21px); @@ -338,6 +303,59 @@ mediaviewTitleMaximizeMacPadding: margins(0px, 4px, 8px, 4px); mediaviewShadowTop: icon{{ "mediaview/shadow_top", windowShadowFg }}; mediaviewShadowBottom: icon{{ "mediaview/shadow_bottom", windowShadowFg }}; +mediaviewSpeedMenu: MediaSpeedMenu(mediaPlayerSpeedMenu) { + dropdown: DropdownMenu(mediaviewDropdownMenu) { + menu: Menu(mediaviewMenu) { + separator: MenuSeparator(mediaviewMenuSeparator) { + fg: mediaviewMenuBgOver; + padding: margins(0px, 4px, 0px, 4px); + width: 6px; + } + itemPadding: margins(54px, 7px, 54px, 9px); + itemFgDisabled: mediaviewTextLinkFg; + } + } + activeCheck: icon {{ "player/player_check", mediaviewTextLinkFg }}; + slider: MediaSlider(defaultContinuousSlider) { + activeFg: mediaviewTextLinkFg; + inactiveFg: mediaviewMenuBgOver; + activeFgOver: mediaviewTextLinkFg; + inactiveFgOver: mediaviewMenuBgOver; + activeFgDisabled: mediaviewMenuBgOver; + receivedTillFg: mediaviewMenuBgOver; + width: 6px; + seekSize: size(6px, 6px); + } + + slow: mediaSpeedSlow; + slowActive: mediaSpeedSlowActive; + normal: mediaSpeedNormal; + normalActive: mediaSpeedNormalActive; + medium: mediaSpeedMedium; + mediumActive: mediaSpeedMediumActive; + fast: mediaSpeedFast; + fastActive: mediaSpeedFastActive; + veryFast: mediaSpeedVeryFast; + veryFastActive: mediaSpeedVeryFastActive; + superFast: mediaSpeedSuperFast; + superFastActive: mediaSpeedSuperFastActive; +} +mediaviewSpeedButton: MediaSpeedButton(mediaPlayerSpeedButton) { + size: size(32px, 32px); + padding: margins(0px, 0px, 0px, 0px); + fg: mediaviewPlaybackIconFg; + overFg: mediaviewPlaybackIconFgOver; + activeFg: mediaviewTextLinkFg; + icon: icon{{ "player/player_speed", mediaviewPlaybackIconFg }}; + ripple: RippleAnimation(defaultRippleAnimation) { + color: mediaviewPlaybackIconRipple; + } + rippleActiveColor: mediaviewPlaybackIconRipple; + rippleRadius: 16px; + menu: mediaviewSpeedMenu; + menuAlign: align(bottomright); +} + themePreviewSize: size(903px, 584px); themePreviewBg: windowBg; themePreviewOverlayOpacity: 0.8; diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp index 339e5332d..905fd1c1b 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.cpp @@ -3743,10 +3743,8 @@ void OverlayWidget::playbackControlsSpeedChanged(float64 speed) { } } -float64 OverlayWidget::playbackControlsCurrentSpeed() { - const auto result = Core::App().settings().videoPlaybackSpeed(); - DEBUG_LOG(("Media playback speed: now %1.").arg(result)); - return result; +float64 OverlayWidget::playbackControlsCurrentSpeed(bool lastNonDefault) { + return Core::App().settings().videoPlaybackSpeed(lastNonDefault); } void OverlayWidget::switchToPip() { diff --git a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h index 7b9dd5788..a70b64f79 100644 --- a/Telegram/SourceFiles/media/view/media_view_overlay_widget.h +++ b/Telegram/SourceFiles/media/view/media_view_overlay_widget.h @@ -204,7 +204,7 @@ private: void playbackControlsVolumeToggled() override; void playbackControlsVolumeChangeFinished() override; void playbackControlsSpeedChanged(float64 speed) override; - float64 playbackControlsCurrentSpeed() override; + float64 playbackControlsCurrentSpeed(bool lastNonDefault) override; void playbackControlsToFullScreen() override; void playbackControlsFromFullScreen() override; void playbackControlsToPictureInPicture() override; diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp index 3b18ba9a6..8ab0eb549 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.cpp @@ -8,13 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "media/view/media_view_playback_controls.h" #include "media/audio/media_audio.h" +#include "media/player/media_player_button.h" +#include "media/player/media_player_dropdown.h" #include "media/view/media_view_playback_progress.h" #include "ui/widgets/labels.h" #include "ui/widgets/continuous_sliders.h" #include "ui/effects/fade_animation.h" #include "ui/widgets/buttons.h" #include "ui/widgets/menu/menu_item_base.h" -#include "ui/widgets/popup_menu.h" #include "ui/text/format_values.h" #include "ui/cached_round_corners.h" #include "lang/lang_keys.h" @@ -22,184 +23,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Media { namespace View { -namespace { - -constexpr auto kMinSpeed = 50; -constexpr auto kMaxSpeed = 200; - -constexpr float64 SpeedShiftToValue(float64 value) { - const auto valueAsSpeedF = value * 100.; - const auto valueAsSpeed = int(valueAsSpeedF + 0.5); // constexpr round. - return float64(valueAsSpeed) / (kMaxSpeed - kMinSpeed); -}; - -constexpr float64 SpeedToValue(float64 value) { - const auto valueAsSpeedF = value * 100.; - const auto valueAsSpeed = int(valueAsSpeedF + 0.5); // constexpr round. - return float64(valueAsSpeed - kMinSpeed) / (kMaxSpeed - kMinSpeed); -}; - -constexpr auto kSpeedStickedValues = - std::array, 5>{{ - { SpeedToValue(0.75), SpeedShiftToValue(0.03) }, - { SpeedToValue(1.00), SpeedShiftToValue(0.05) }, - { SpeedToValue(1.25), SpeedShiftToValue(0.03) }, - { SpeedToValue(1.50), SpeedShiftToValue(0.03) }, - { SpeedToValue(1.75), SpeedShiftToValue(0.03) }, - }}; - -class MenuSpeedItem final : public Ui::Menu::ItemBase { -public: - MenuSpeedItem( - not_null parent, - const style::Menu &st, - float64 startSpeed); - - not_null action() const override; - bool isEnabled() const override; - - [[nodiscard]] rpl::producer changeSpeedRequests() const; - -protected: - int contentHeight() const override; - -private: - float64 computeSpeed(float64 value) const; - QString speedString(float64 value) const; - - QRect _itemRect; - QRect _textRect; - - const style::MediaSlider &_sliderSt; - const base::unique_qptr _slider; - const not_null _dummyAction; - const int _lineCount; - const int _height; - - rpl::event_stream _changeSpeedRequests; - -}; - -MenuSpeedItem::MenuSpeedItem( - not_null parent, - const style::Menu &st, - float64 startSpeed) -: Ui::Menu::ItemBase(parent, st) -, _sliderSt(st::mediaviewPlayback) -, _slider(base::make_unique_q( - this, - _sliderSt)) -, _dummyAction(new QAction(parent)) -, _lineCount(std::ceil(st.itemStyle.font->width(speedString(0.9)) - / float(st.widthMax))) -, _height(st.itemPadding.top() * 2 - + st.itemStyle.font->height * _lineCount - + _sliderSt.seekSize.height() - + st.itemPadding.bottom() * 2) { - - initResizeHook(parent->sizeValue()); - enableMouseSelecting(); - enableMouseSelecting(_slider.get()); - - _slider->setAlwaysDisplayMarker(true); - _slider->setValue((base::SafeRound(startSpeed * 100.) - kMinSpeed) - / (kMaxSpeed - kMinSpeed)); - - for (const auto &sticked : kSpeedStickedValues) { - _slider->addDivider(sticked.first, st::speedSliderDividerSize); - } - //_slider->addDivider( - // kSpeedStickedValues[1].first, - // st::speedSliderDividerSize); - - { - const auto goodWidth = st.itemPadding.left() - + st.itemPadding.right() - + st.itemStyle.font->width(speedString(0.9)); - setMinWidth(std::clamp(goodWidth, st.widthMin, st.widthMax)); - } - - sizeValue( - ) | rpl::start_with_next([=](const QSize &size) { - const auto geometry = QRect(QPoint(), size); - _itemRect = geometry - st.itemPadding; - - const auto height = _itemRect.height(); - const auto penWidth = QPen(st.itemBgOver).width(); - _textRect = _itemRect - - style::margins( - -penWidth, - 0, - -penWidth, - height - st.itemStyle.font->height * _lineCount); - - const auto sliderGeometry = _itemRect - - style::margins(0, height - _sliderSt.seekSize.height(), 0, 0); - _slider->setGeometry(sliderGeometry); - }, lifetime()); - - paintRequest( - ) | rpl::start_with_next([=](const QRect &clip) { - auto p = QPainter(this); - - const auto selected = isSelected(); - p.fillRect(clip, selected ? st.itemBgOver : st.itemBg); - - const auto value = _slider->value(); - - p.setPen(selected ? st.itemFgOver : st.itemFg); - p.setFont(st.itemStyle.font); - p.drawText(_textRect, speedString(value), style::al_left); - }, lifetime()); - - _slider->setChangeProgressCallback([=](float64 value) { - update(_textRect); - }); - - _slider->setChangeFinishedCallback([=](float64 value) { - _changeSpeedRequests.fire_copy(computeSpeed(value)); - }); - - _slider->setAdjustCallback([=](float64 value) { - for (const auto &snap : kSpeedStickedValues) { - if (value > (snap.first - snap.second) - && value < (snap.first + snap.second)) { - return snap.first; - } - } - return value; - }); -} - -float64 MenuSpeedItem::computeSpeed(float64 value) const { - return anim::interpolate(kMinSpeed, kMaxSpeed, std::clamp(value, 0., 1.)) - / 100.; -} - -QString MenuSpeedItem::speedString(float64 value) const { - return tr::lng_mediaview_playback_speed( - tr::now, - lt_speed, - QString::number(computeSpeed(value), 'f', 2) + 'x'); -} - -not_null MenuSpeedItem::action() const { - return _dummyAction; -} - -bool MenuSpeedItem::isEnabled() const { - return true; -} - -int MenuSpeedItem::contentHeight() const { - return _height; -} - -rpl::producer MenuSpeedItem::changeSpeedRequests() const { - return _changeSpeedRequests.events(); -} - -} // namespace PlaybackControls::PlaybackControls( QWidget *parent, @@ -211,12 +34,18 @@ PlaybackControls::PlaybackControls( , _playbackProgress(std::make_unique()) , _volumeToggle(this, st::mediaviewVolumeToggle) , _volumeController(this, st::mediaviewPlayback) -, _menuToggle(this, st::mediaviewMenuToggle) +, _speedToggle(this, st::mediaviewSpeedButton) , _fullScreenToggle(this, st::mediaviewFullScreenButton) , _pictureInPicture(this, st::mediaviewPipButton) , _playedAlready(this, st::mediaviewPlayProgressLabel) , _toPlayLeft(this, st::mediaviewPlayProgressLabel) -, _menuStyle(st::mediaviewControlsPopupMenu) +, _speedController( + std::make_unique( + _speedToggle.data(), + parent, + [=](bool) {}, + [=](bool lastNonDefault) { return speedLookup(lastNonDefault); }, + [=](float64 speed) { saveSpeed(speed); })) , _fadeAnimation(std::make_unique(this)) { _fadeAnimation->show(); _fadeAnimation->setFinishedCallback([=] { @@ -229,9 +58,6 @@ PlaybackControls::PlaybackControls( _pictureInPicture->addClickHandler([=] { _delegate->playbackControlsToPictureInPicture(); }); - _menuToggle->addClickHandler([=] { - showMenu(); - }); _volumeController->setValue(_delegate->playbackControlsCurrentVolume()); _volumeController->setChangeProgressCallback([=](float64 value) { @@ -354,33 +180,13 @@ void PlaybackControls::fadeUpdated(float64 opacity) { _volumeController->setFadeOpacity(opacity); } -void PlaybackControls::showMenu() { - if (_menu) { - _menu = nullptr; - return; - } - _menu.emplace(this, _menuStyle); +float64 PlaybackControls::speedLookup(bool lastNonDefault) const { + return _delegate->playbackControlsCurrentSpeed(lastNonDefault); +} - if (Media::Audio::SupportsSpeedControl()) { - auto speedItem = base::make_unique_q( - _menu, - _menuStyle.menu, - _delegate->playbackControlsCurrentSpeed()); - speedItem->changeSpeedRequests( - ) | rpl::start_with_next([=](float64 speed) { - updatePlaybackSpeed(speed); - }, speedItem->lifetime()); - _menu->addAction(std::move(speedItem)); - _menu->addSeparator(); - } - - _menu->addAction(tr::lng_mediaview_rotate_video(tr::now), [=] { - _delegate->playbackControlsRotate(); - }); - - _menu->setForcedOrigin(Ui::PanelAnimation::Origin::BottomLeft); - _menu->popup(mapToGlobal(_menuToggle->geometry().topLeft())); +void PlaybackControls::saveSpeed(float64 speed) { + _delegate->playbackControlsSpeedChanged(speed); } void PlaybackControls::updatePlaybackSpeed(float64 speed) { @@ -524,7 +330,7 @@ void PlaybackControls::setInFullScreen(bool inFullScreen) { void PlaybackControls::resizeEvent(QResizeEvent *e) { const auto textSkip = st::mediaviewPlayProgressSkip; const auto textLeft = st::mediaviewPlayProgressLeft; - const auto textTop = st::mediaviewPlaybackTop + (_playbackSlider->height() - _playedAlready->height()) / 2; + const auto textTop = st::mediaviewPlayProgressTop; _playedAlready->moveToLeft(textLeft + textSkip, textTop); _toPlayLeft->moveToRight(textLeft + textSkip, textTop); const auto remove = 2 * textLeft + 4 * textSkip + _playedAlready->width() + _toPlayLeft->width(); @@ -536,16 +342,16 @@ void PlaybackControls::resizeEvent(QResizeEvent *e) { (width() - _playPauseResume->width()) / 2, st::mediaviewPlayButtonTop); - auto right = st::mediaviewMenuToggleSkip; - _menuToggle->moveToRight(right, st::mediaviewButtonsTop); - right += _menuToggle->width() + st::mediaviewPipButtonSkip; + auto right = st::mediaviewButtonsRight; + _speedToggle->moveToRight(right, st::mediaviewButtonsTop); + right += _speedToggle->width() + st::mediaviewPipButtonSkip; _pictureInPicture->moveToRight(right, st::mediaviewButtonsTop); right += _pictureInPicture->width() + st::mediaviewFullScreenButtonSkip; _fullScreenToggle->moveToRight(right, st::mediaviewButtonsTop); updateDownloadProgressPosition(); - auto left = st::mediaviewVolumeToggleSkip; + auto left = st::mediaviewVolumeToggleLeft; _volumeToggle->moveToLeft(left, st::mediaviewVolumeTop); left += _volumeToggle->width() + st::mediaviewVolumeSkip; _volumeController->resize( @@ -586,7 +392,7 @@ void PlaybackControls::mousePressEvent(QMouseEvent *e) { } bool PlaybackControls::hasMenu() const { - return _menu != nullptr; + return _speedController->menu() != nullptr; } bool PlaybackControls::dragging() const { @@ -594,7 +400,7 @@ bool PlaybackControls::dragging() const { || _playbackSlider->isChanging() || _playPauseResume->isOver() || _volumeToggle->isOver() - || _menuToggle->isOver() + || _speedToggle->isOver() || _fullScreenToggle->isOver() || _pictureInPicture->isOver(); } diff --git a/Telegram/SourceFiles/media/view/media_view_playback_controls.h b/Telegram/SourceFiles/media/view/media_view_playback_controls.h index b972d217a..5f79cba52 100644 --- a/Telegram/SourceFiles/media/view/media_view_playback_controls.h +++ b/Telegram/SourceFiles/media/view/media_view_playback_controls.h @@ -23,6 +23,8 @@ class PopupMenu; namespace Media { namespace Player { struct TrackState; +class SpeedButton; +class SpeedController; } // namespace Player namespace View { @@ -42,7 +44,8 @@ public: virtual void playbackControlsVolumeToggled() = 0; virtual void playbackControlsVolumeChangeFinished() = 0; virtual void playbackControlsSpeedChanged(float64 speed) = 0; - [[nodiscard]] virtual float64 playbackControlsCurrentSpeed() = 0; + [[nodiscard]] virtual float64 playbackControlsCurrentSpeed( + bool lastNonDefault) = 0; virtual void playbackControlsToFullScreen() = 0; virtual void playbackControlsFromFullScreen() = 0; virtual void playbackControlsToPictureInPicture() = 0; @@ -50,6 +53,7 @@ public: }; PlaybackControls(QWidget *parent, not_null delegate); + ~PlaybackControls(); void showAnimated(); void hideAnimated(); @@ -60,8 +64,6 @@ public: [[nodiscard]] bool hasMenu() const; [[nodiscard]] bool dragging() const; - ~PlaybackControls(); - protected: void resizeEvent(QResizeEvent *e) override; void paintEvent(QPaintEvent *e) override; @@ -86,9 +88,11 @@ private: void updatePlayPauseResumeState(const Player::TrackState &state); void updateTimeTexts(const Player::TrackState &state); void refreshTimeTexts(); - void showMenu(); - not_null _delegate; + [[nodiscard]] float64 speedLookup(bool lastNonDefault) const; + void saveSpeed(float64 speed); + + const not_null _delegate; bool _inFullScreen = false; bool _showPause = false; @@ -106,15 +110,13 @@ private: std::unique_ptr _receivedTillProgress; object_ptr _volumeToggle; object_ptr _volumeController; - object_ptr _menuToggle; + object_ptr _speedToggle; object_ptr _fullScreenToggle; object_ptr _pictureInPicture; object_ptr _playedAlready; object_ptr _toPlayLeft; object_ptr _downloadProgress = { nullptr }; - - const style::PopupMenu &_menuStyle; - base::unique_qptr _menu; + std::unique_ptr _speedController; std::unique_ptr _fadeAnimation; }; diff --git a/Telegram/SourceFiles/overview/overview.style b/Telegram/SourceFiles/overview/overview.style index 1657d175d..82a9c70e6 100644 --- a/Telegram/SourceFiles/overview/overview.style +++ b/Telegram/SourceFiles/overview/overview.style @@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL using "ui/basic.style"; using "ui/chat/chat.style"; using "ui/widgets/widgets.style"; -using "media/view/media_view.style"; using "boxes/boxes.style"; OverviewFileLayout { diff --git a/Telegram/SourceFiles/ui/menu_icons.style b/Telegram/SourceFiles/ui/menu_icons.style index 999df51ad..7be43b08f 100644 --- a/Telegram/SourceFiles/ui/menu_icons.style +++ b/Telegram/SourceFiles/ui/menu_icons.style @@ -131,3 +131,29 @@ menuIconDisableAttention: icon {{ "menu/disable", menuIconAttentionColor }}; menuIconReportAttention: icon {{ "menu/report", menuIconAttentionColor }}; menuIconBlockSettings: icon {{ "menu/block", windowBgActive }}; + +playerSpeedSlow: icon {{ "player/speed/audiospeed_menu_0.5", menuIconColor }}; +playerSpeedSlowActive: icon {{ "player/speed/audiospeed_menu_0.5", mediaPlayerActiveFg }}; +playerSpeedNormal: icon {{ "player/speed/audiospeed_menu_1.0", menuIconColor }}; +playerSpeedNormalActive: icon {{ "player/speed/audiospeed_menu_1.0", mediaPlayerActiveFg }}; +playerSpeedMedium: icon {{ "player/speed/audiospeed_menu_1.2", menuIconColor }}; +playerSpeedMediumActive: icon {{ "player/speed/audiospeed_menu_1.2", mediaPlayerActiveFg }}; +playerSpeedFast: icon {{ "player/speed/audiospeed_menu_1.5", menuIconColor }}; +playerSpeedFastActive: icon {{ "player/speed/audiospeed_menu_1.5", mediaPlayerActiveFg }}; +playerSpeedVeryFast: icon {{ "player/speed/audiospeed_menu_1.7", menuIconColor }}; +playerSpeedVeryFastActive: icon {{ "player/speed/audiospeed_menu_1.7", mediaPlayerActiveFg }}; +playerSpeedSuperFast: icon {{ "player/speed/audiospeed_menu_2.0", menuIconColor }}; +playerSpeedSuperFastActive: icon {{ "player/speed/audiospeed_menu_2.0", mediaPlayerActiveFg }}; + +mediaSpeedSlow: icon {{ "player/speed/audiospeed_menu_0.5", mediaviewMenuFg }}; +mediaSpeedSlowActive: icon {{ "player/speed/audiospeed_menu_0.5", mediaviewTextLinkFg }}; +mediaSpeedNormal: icon {{ "player/speed/audiospeed_menu_1.0", mediaviewMenuFg }}; +mediaSpeedNormalActive: icon {{ "player/speed/audiospeed_menu_1.0", mediaviewTextLinkFg }}; +mediaSpeedMedium: icon {{ "player/speed/audiospeed_menu_1.2", mediaviewMenuFg }}; +mediaSpeedMediumActive: icon {{ "player/speed/audiospeed_menu_1.2", mediaviewTextLinkFg }}; +mediaSpeedFast: icon {{ "player/speed/audiospeed_menu_1.5", mediaviewMenuFg }}; +mediaSpeedFastActive: icon {{ "player/speed/audiospeed_menu_1.5", mediaviewTextLinkFg }}; +mediaSpeedVeryFast: icon {{ "player/speed/audiospeed_menu_1.7", mediaviewMenuFg }}; +mediaSpeedVeryFastActive: icon {{ "player/speed/audiospeed_menu_1.7", mediaviewTextLinkFg }}; +mediaSpeedSuperFast: icon {{ "player/speed/audiospeed_menu_2.0", mediaviewMenuFg }}; +mediaSpeedSuperFastActive: icon {{ "player/speed/audiospeed_menu_2.0", mediaviewTextLinkFg }}; diff --git a/Telegram/cmake/td_ui.cmake b/Telegram/cmake/td_ui.cmake index fea8a0e0c..be9ad16a0 100644 --- a/Telegram/cmake/td_ui.cmake +++ b/Telegram/cmake/td_ui.cmake @@ -125,6 +125,8 @@ PRIVATE media/player/media_player_dropdown.cpp media/player/media_player_dropdown.h + media/media_common.h + menu/menu_check_item.cpp menu/menu_check_item.h menu/menu_ttl.cpp diff --git a/Telegram/lib_ui b/Telegram/lib_ui index 62a62d1fb..dec1cd8ce 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit 62a62d1fb5abe9dc1e6b9f89af1ccef6fef33c52 +Subproject commit dec1cd8cea24e396c37c327929c0135d46541626