Implement new voice speed change control design.
|
@ -946,8 +946,6 @@ PRIVATE
|
||||||
media/audio/media_audio_track.h
|
media/audio/media_audio_track.h
|
||||||
media/audio/media_child_ffmpeg_loader.cpp
|
media/audio/media_child_ffmpeg_loader.cpp
|
||||||
media/audio/media_child_ffmpeg_loader.h
|
media/audio/media_child_ffmpeg_loader.h
|
||||||
media/player/media_player_button.cpp
|
|
||||||
media/player/media_player_button.h
|
|
||||||
media/player/media_player_float.cpp
|
media/player/media_player_float.cpp
|
||||||
media/player/media_player_float.h
|
media/player/media_player_float.h
|
||||||
media/player/media_player_instance.cpp
|
media/player/media_player_instance.cpp
|
||||||
|
|
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 410 B After Width: | Height: | Size: 412 B |
Before Width: | Height: | Size: 593 B After Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 764 B |
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 307 B |
Before Width: | Height: | Size: 510 B After Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 775 B After Width: | Height: | Size: 804 B |
Before Width: | Height: | Size: 540 B After Width: | Height: | Size: 622 B |
Before Width: | Height: | Size: 995 B After Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 412 B After Width: | Height: | Size: 534 B |
Before Width: | Height: | Size: 665 B After Width: | Height: | Size: 847 B |
Before Width: | Height: | Size: 951 B After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 532 B |
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 647 B After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 391 B |
Before Width: | Height: | Size: 527 B After Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 832 B |
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 230 B |
Before Width: | Height: | Size: 306 B After Width: | Height: | Size: 310 B |
Before Width: | Height: | Size: 422 B After Width: | Height: | Size: 427 B |
Before Width: | Height: | Size: 298 B After Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 437 B After Width: | Height: | Size: 478 B |
Before Width: | Height: | Size: 609 B After Width: | Height: | Size: 646 B |
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 534 B |
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 888 B |
Before Width: | Height: | Size: 1,011 B After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 531 B |
Before Width: | Height: | Size: 731 B After Width: | Height: | Size: 902 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 212 B |
Before Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 514 B After Width: | Height: | Size: 396 B |
Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 815 B |
BIN
Telegram/Resources/icons/player/player_speed.png
Normal file
After Width: | Height: | Size: 152 B |
BIN
Telegram/Resources/icons/player/player_speed@2x.png
Normal file
After Width: | Height: | Size: 208 B |
BIN
Telegram/Resources/icons/player/player_speed@3x.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_0.5.png
Normal file
After Width: | Height: | Size: 536 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_0.5@2x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_0.5@3x.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.0.png
Normal file
After Width: | Height: | Size: 478 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.0@2x.png
Normal file
After Width: | Height: | Size: 947 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.0@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.2.png
Normal file
After Width: | Height: | Size: 502 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.2@2x.png
Normal file
After Width: | Height: | Size: 939 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.2@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.5.png
Normal file
After Width: | Height: | Size: 522 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.5@2x.png
Normal file
After Width: | Height: | Size: 1,020 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.5@3x.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.7.png
Normal file
After Width: | Height: | Size: 475 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.7@2x.png
Normal file
After Width: | Height: | Size: 889 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_1.7@3x.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_2.0.png
Normal file
After Width: | Height: | Size: 463 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_2.0@2x.png
Normal file
After Width: | Height: | Size: 817 B |
BIN
Telegram/Resources/icons/player/speed/audiospeed_menu_2.0@3x.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 559 B |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 542 B |
Before Width: | Height: | Size: 1,017 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 530 B |
Before Width: | Height: | Size: 928 B |
Before Width: | Height: | Size: 1.4 KiB |
|
@ -3552,8 +3552,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
"lng_voice_speed_slow" = "Slow";
|
"lng_voice_speed_slow" = "Slow";
|
||||||
"lng_voice_speed_normal" = "Normal";
|
"lng_voice_speed_normal" = "Normal";
|
||||||
|
"lng_voice_speed_medium" = "Medium";
|
||||||
"lng_voice_speed_fast" = "Fast";
|
"lng_voice_speed_fast" = "Fast";
|
||||||
"lng_voice_speed_very_fast" = "Very fast";
|
"lng_voice_speed_very_fast" = "Very fast";
|
||||||
|
"lng_voice_speed_super_fast" = "Super fast";
|
||||||
|
|
||||||
"lng_view_button_user" = "View user";
|
"lng_view_button_user" = "View user";
|
||||||
"lng_view_button_bot" = "View bot";
|
"lng_view_button_bot" = "View bot";
|
||||||
|
|
|
@ -3193,6 +3193,9 @@ void HistoryItem::createComponents(const MTPDmessage &data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto id = data.vreply_to_msg_id().v;
|
const auto id = data.vreply_to_msg_id().v;
|
||||||
|
if (data.is_reply_to_scheduled()) {
|
||||||
|
int a = 0;
|
||||||
|
}
|
||||||
config.replyTo = data.is_reply_to_scheduled()
|
config.replyTo = data.is_reply_to_scheduled()
|
||||||
? _history->owner().scheduledMessages().localMessageId(id)
|
? _history->owner().scheduledMessages().localMessageId(id)
|
||||||
: id;
|
: id;
|
||||||
|
|
|
@ -491,7 +491,7 @@ void Mixer::Track::updateWithSpeedPosition() {
|
||||||
int64 Mixer::Track::SpeedIndependentPosition(
|
int64 Mixer::Track::SpeedIndependentPosition(
|
||||||
int64 position,
|
int64 position,
|
||||||
float64 speed) {
|
float64 speed) {
|
||||||
Expects(speed < 2.5);
|
Expects(speed <= Audio::kSpeedMax);
|
||||||
|
|
||||||
return int64(base::SafeRound(position * speed));
|
return int64(base::SafeRound(position * speed));
|
||||||
}
|
}
|
||||||
|
@ -499,7 +499,7 @@ int64 Mixer::Track::SpeedIndependentPosition(
|
||||||
int64 Mixer::Track::SpeedDependentPosition(
|
int64 Mixer::Track::SpeedDependentPosition(
|
||||||
int64 position,
|
int64 position,
|
||||||
float64 speed) {
|
float64 speed) {
|
||||||
Expects(speed >= 0.5);
|
Expects(speed >= Audio::kSpeedMin);
|
||||||
|
|
||||||
return int64(base::SafeRound(position / speed));
|
return int64(base::SafeRound(position / speed));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,50 @@ using "ui/basic.style";
|
||||||
using "ui/widgets/widgets.style";
|
using "ui/widgets/widgets.style";
|
||||||
using "overview/overview.style";
|
using "overview/overview.style";
|
||||||
|
|
||||||
|
MediaPlayerButton {
|
||||||
|
playPosition: point;
|
||||||
|
playOuter: size;
|
||||||
|
pausePosition: point;
|
||||||
|
pauseOuter: size;
|
||||||
|
pauseStroke: pixels;
|
||||||
|
cancelPosition: point;
|
||||||
|
cancelOuter: size;
|
||||||
|
cancelStroke: pixels;
|
||||||
|
|
||||||
|
rippleAreaPosition: point;
|
||||||
|
rippleAreaSize: pixels;
|
||||||
|
ripple: RippleAnimation;
|
||||||
|
|
||||||
|
duration: int;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSpeedButton {
|
||||||
|
width: pixels;
|
||||||
|
height: pixels;
|
||||||
|
font: font;
|
||||||
|
icon: icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
MediaSpeedMenu {
|
||||||
|
menu: Menu;
|
||||||
|
iconFg: color;
|
||||||
|
iconFgActive: color;
|
||||||
|
textFgActive: color;
|
||||||
|
activeCheck: icon;
|
||||||
|
activeCheckSkip: pixels;
|
||||||
|
sliderStyle: TextStyle;
|
||||||
|
sliderPadding: margins;
|
||||||
|
sliderWidth: pixels;
|
||||||
|
slider: MediaSlider;
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaSpeedButton: MediaSpeedButton {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
font: font(11px semibold);
|
||||||
|
icon: icon{{ "player/player_speed", menuIconFg }};
|
||||||
|
}
|
||||||
|
|
||||||
mediaPlayerButton: MediaPlayerButton {
|
mediaPlayerButton: MediaPlayerButton {
|
||||||
playPosition: point(2px, 0px);
|
playPosition: point(2px, 0px);
|
||||||
playOuter: size(17px, 15px);
|
playOuter: size(17px, 15px);
|
||||||
|
@ -25,6 +69,8 @@ mediaPlayerButton: MediaPlayerButton {
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: lightButtonBgOver;
|
color: lightButtonBgOver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
duration: 200;
|
||||||
}
|
}
|
||||||
mediaPlayerWideWidth: 460px;
|
mediaPlayerWideWidth: 460px;
|
||||||
mediaPlayerHeight: 35px;
|
mediaPlayerHeight: 35px;
|
||||||
|
@ -96,59 +142,64 @@ mediaPlayerCancelIcon: icon{
|
||||||
{ "player/panel_close", mediaPlayerActiveFg }
|
{ "player/panel_close", mediaPlayerActiveFg }
|
||||||
};
|
};
|
||||||
|
|
||||||
mediaPlayerSpeedButton: IconButton {
|
mediaPlayerSpeedSize: size(30px, 30px);
|
||||||
width: 31px;
|
mediaPlayerSpeedRadius: 4px;
|
||||||
height: 30px;
|
mediaPlayerSpeedRipple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: lightButtonBgOver;
|
||||||
icon: icon {
|
|
||||||
{ "player/voice_speed/voice_speed2", mediaPlayerActiveFg }
|
|
||||||
};
|
|
||||||
iconPosition: point(3px, 10px);
|
|
||||||
|
|
||||||
rippleAreaPosition: point(3px, 5px);
|
|
||||||
rippleAreaSize: 25px;
|
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
|
||||||
color: lightButtonBgOver;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mediaPlayerSpeedDisabledIcon: icon {
|
|
||||||
{ "player/voice_speed/voice_speed2", menuIconFg }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedDisabledIconOver: icon {
|
|
||||||
{ "player/voice_speed/voice_speed2", menuIconFgOver }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedSlowIcon: icon {
|
|
||||||
{ "player/voice_speed/voice_speed0.5", mediaPlayerActiveFg }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedSlowDisabledIcon: icon {
|
|
||||||
{ "player/voice_speed/voice_speed0.5", menuIconFg }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedSlowDisabledIconOver: icon {
|
|
||||||
{ "player/voice_speed/voice_speed0.5", menuIconFgOver }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedFastIcon: icon {
|
|
||||||
{ "player/voice_speed/voice_speed1.5", mediaPlayerActiveFg }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedFastDisabledIcon: icon {
|
|
||||||
{ "player/voice_speed/voice_speed1.5", menuIconFg }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedFastDisabledIconOver: icon {
|
|
||||||
{ "player/voice_speed/voice_speed1.5", menuIconFgOver }
|
|
||||||
};
|
|
||||||
mediaPlayerSpeedDisabledRippleBg: windowBgOver;
|
mediaPlayerSpeedDisabledRippleBg: windowBgOver;
|
||||||
|
|
||||||
mediaPlayerMenu: DropdownMenu(defaultDropdownMenu) {
|
mediaPlayerMenu: DropdownMenu(defaultDropdownMenu) {
|
||||||
wrap: InnerDropdown(defaultInnerDropdown) {
|
wrap: InnerDropdown(defaultInnerDropdown) {
|
||||||
scrollPadding: margins(0px, 8px, 0px, 8px);
|
scrollPadding: margins(0px, 4px, 0px, 4px);
|
||||||
padding: margins(10px, 2px, 10px, 10px);
|
padding: margins(10px, 2px, 10px, 10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mediaPlayerSpeedMenu: Menu(defaultMenu) {
|
|
||||||
itemIconPosition: point(6px, 5px);
|
|
||||||
itemPadding: margins(34px, 8px, 17px, 7px);
|
|
||||||
}
|
|
||||||
mediaPlayerMenuCheck: icon {{ "player/player_check", mediaPlayerActiveFg }};
|
mediaPlayerMenuCheck: icon {{ "player/player_check", mediaPlayerActiveFg }};
|
||||||
|
|
||||||
|
mediaSpeedMenu: MediaSpeedMenu {
|
||||||
|
menu: Menu(menuWithIcons) {
|
||||||
|
separator: MenuSeparator(defaultMenuSeparator) {
|
||||||
|
padding: margins(0px, 4px, 0px, 4px);
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
itemPadding: margins(54px, 7px, 54px, 9px);
|
||||||
|
itemFgDisabled: mediaPlayerActiveFg;
|
||||||
|
}
|
||||||
|
iconFg: menuIconColor;
|
||||||
|
iconFgActive: mediaPlayerActiveFg;
|
||||||
|
textFgActive: mediaPlayerActiveFg;
|
||||||
|
activeCheck: mediaPlayerMenuCheck;
|
||||||
|
activeCheckSkip: 8px;
|
||||||
|
sliderStyle: TextStyle(defaultTextStyle) {
|
||||||
|
font: font(12px semibold);
|
||||||
|
}
|
||||||
|
sliderPadding: margins(50px, 8px, 12px, 8px);
|
||||||
|
sliderWidth: 122px;
|
||||||
|
slider: MediaSlider(defaultContinuousSlider) {
|
||||||
|
activeFg: mediaPlayerActiveFg;
|
||||||
|
inactiveFg: windowBgOver;
|
||||||
|
activeFgOver: mediaPlayerActiveFg;
|
||||||
|
inactiveFgOver: windowBgOver;
|
||||||
|
activeFgDisabled: windowBgOver;
|
||||||
|
receivedTillFg: windowBgOver;
|
||||||
|
width: 6px;
|
||||||
|
seekSize: size(6px, 6px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 {
|
mediaPlayerVolumeIcon0: icon {
|
||||||
{ "player/player_mini_off", mediaPlayerActiveFg },
|
{ "player/player_mini_off", mediaPlayerActiveFg },
|
||||||
};
|
};
|
||||||
|
@ -211,8 +262,6 @@ mediaPlayerPlayback: FilledSlider {
|
||||||
duration: 150;
|
duration: 150;
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaPlayerButtonTransformDuration: 200;
|
|
||||||
|
|
||||||
mediaPlayerPanelMarginLeft: 10px;
|
mediaPlayerPanelMarginLeft: 10px;
|
||||||
mediaPlayerPanelMarginBottom: 10px;
|
mediaPlayerPanelMarginBottom: 10px;
|
||||||
mediaPlayerPanelWidth: 344px;
|
mediaPlayerPanelWidth: 344px;
|
||||||
|
|
|
@ -8,18 +8,30 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/player/media_player_button.h"
|
#include "media/player/media_player_button.h"
|
||||||
|
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_media_player.h"
|
||||||
|
|
||||||
namespace Media {
|
#include <QtCore/QtMath>
|
||||||
namespace Player {
|
|
||||||
|
|
||||||
PlayButtonLayout::PlayButtonLayout(const style::MediaPlayerButton &st, Fn<void()> callback)
|
namespace Media::Player {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
[[nodiscard]] QString SpeedText(float64 speed) {
|
||||||
|
return QString::number(base::SafeRound(speed * 10) / 10.) + 'X';
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
PlayButtonLayout::PlayButtonLayout(
|
||||||
|
const style::MediaPlayerButton &st,
|
||||||
|
Fn<void()> callback)
|
||||||
: _st(st)
|
: _st(st)
|
||||||
, _callback(std::move(callback)) {
|
, _callback(std::move(callback)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayButtonLayout::setState(State state) {
|
void PlayButtonLayout::setState(State state) {
|
||||||
if (_nextState == state) return;
|
if (_nextState == state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_nextState = state;
|
_nextState = state;
|
||||||
if (!_transformProgress.animating()) {
|
if (!_transformProgress.animating()) {
|
||||||
|
@ -238,8 +250,95 @@ void PlayButtonLayout::animationCallback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayButtonLayout::startTransform(float64 from, float64 to) {
|
void PlayButtonLayout::startTransform(float64 from, float64 to) {
|
||||||
_transformProgress.start([this] { animationCallback(); }, from, to, st::mediaPlayerButtonTransformDuration);
|
_transformProgress.start(
|
||||||
|
[=] { animationCallback(); },
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
_st.duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Player
|
SpeedButtonLayout::SpeedButtonLayout(
|
||||||
} // namespace Media
|
const style::MediaSpeedButton &st,
|
||||||
|
Fn<void()> callback,
|
||||||
|
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;
|
||||||
|
_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
p.setPen(color);
|
||||||
|
p.setFont(_st.font);
|
||||||
|
|
||||||
|
p.drawText(
|
||||||
|
QPointF(
|
||||||
|
(_st.width - _textWidth) / 2.,
|
||||||
|
(_st.height - _metrics.height()) / 2. + _metrics.ascent()),
|
||||||
|
_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedButtonLayout::animationCallback() {
|
||||||
|
if (!_transformProgress.animating()) {
|
||||||
|
const auto finalSpeed = _nextSpeed;
|
||||||
|
_nextSpeed = _speed;
|
||||||
|
setSpeed(finalSpeed);
|
||||||
|
}
|
||||||
|
_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedButtonLayout::startTransform(float64 from, float64 to) {
|
||||||
|
// No animation for now.
|
||||||
|
_transformProgress.stop();
|
||||||
|
animationCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Media::Player
|
||||||
|
|
|
@ -7,12 +7,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/abstract_button.h"
|
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "styles/style_media_player.h"
|
|
||||||
|
|
||||||
namespace Media {
|
#include <QtGui/QFontMetrics>
|
||||||
namespace Player {
|
|
||||||
|
namespace style {
|
||||||
|
struct MediaPlayerButton;
|
||||||
|
struct MediaSpeedButton;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
|
namespace Media::Player {
|
||||||
|
|
||||||
class PlayButtonLayout {
|
class PlayButtonLayout {
|
||||||
public:
|
public:
|
||||||
|
@ -48,5 +52,40 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Player
|
class SpeedButtonLayout {
|
||||||
} // namespace Media
|
public:
|
||||||
|
SpeedButtonLayout(
|
||||||
|
const style::MediaSpeedButton &st,
|
||||||
|
Fn<void()> callback,
|
||||||
|
float64 speed);
|
||||||
|
|
||||||
|
void setSpeed(float64 speed);
|
||||||
|
void finishTransform();
|
||||||
|
void paint(QPainter &p, const QColor &color);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void animationCallback();
|
||||||
|
void startTransform(float64 from, float64 to);
|
||||||
|
|
||||||
|
const style::MediaSpeedButton &_st;
|
||||||
|
|
||||||
|
float64 _speed = 1.;
|
||||||
|
float64 _oldSpeed = 1.;
|
||||||
|
float64 _nextSpeed = 1.;
|
||||||
|
std::optional<QColor> _lastPaintColor;
|
||||||
|
std::optional<QColor> _oldColor;
|
||||||
|
Ui::Animations::Simple _transformProgress;
|
||||||
|
bool _transformBackward = false;
|
||||||
|
|
||||||
|
QFontMetricsF _metrics;
|
||||||
|
|
||||||
|
QString _text;
|
||||||
|
float64 _textWidth = 0;
|
||||||
|
QString _oldText;
|
||||||
|
float64 _oldTextWidth = 0;
|
||||||
|
|
||||||
|
Fn<void()> _callback;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Media::Player
|
||||||
|
|
|
@ -7,12 +7,213 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "media/player/media_player_dropdown.h"
|
#include "media/player/media_player_dropdown.h"
|
||||||
|
|
||||||
|
#include "base/timer.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
#include "ui/cached_round_corners.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/shadow.h"
|
#include "ui/widgets/shadow.h"
|
||||||
|
#include "ui/painter.h"
|
||||||
#include "styles/style_media_player.h"
|
#include "styles/style_media_player.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
|
|
||||||
|
#include "base/debug_log.h"
|
||||||
|
|
||||||
namespace Media::Player {
|
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) {
|
||||||
|
return (speed - kSpeedMin) / (kSpeedMax - kSpeedMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] float64 SliderValueToSpeed(float64 value) {
|
||||||
|
const auto speed = value * (kSpeedMax - kSpeedMin) + kSpeedMin;
|
||||||
|
return base::SafeRound(speed * 10) / 10.;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto kSpeedStickedValues =
|
||||||
|
std::array<std::pair<float64, float64>, 7>{{
|
||||||
|
{ 0.8, 0.05 },
|
||||||
|
{ 1.0, 0.05 },
|
||||||
|
{ 1.2, 0.05 },
|
||||||
|
{ 1.5, 0.05 },
|
||||||
|
{ 1.7, 0.05 },
|
||||||
|
{ 2.0, 0.05 },
|
||||||
|
{ 2.2, 0.05 },
|
||||||
|
}};
|
||||||
|
|
||||||
|
class SpeedSliderItem final : public Ui::Menu::ItemBase {
|
||||||
|
public:
|
||||||
|
SpeedSliderItem(
|
||||||
|
not_null<RpWidget*> parent,
|
||||||
|
const style::MediaSpeedMenu &st,
|
||||||
|
rpl::producer<float64> value);
|
||||||
|
|
||||||
|
not_null<QAction*> action() const override;
|
||||||
|
bool isEnabled() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] float64 current() const;
|
||||||
|
[[nodiscard]] rpl::producer<float64> changing() const;
|
||||||
|
[[nodiscard]] rpl::producer<float64> changed() const;
|
||||||
|
[[nodiscard]] rpl::producer<float64> debouncedChanges() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int contentHeight() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setExternalValue(float64 speed);
|
||||||
|
void setSliderValue(float64 speed);
|
||||||
|
|
||||||
|
const base::unique_qptr<Ui::MediaSlider> _slider;
|
||||||
|
const not_null<QAction*> _dummyAction;
|
||||||
|
const style::MediaSpeedMenu &_st;
|
||||||
|
Ui::Text::String _text;
|
||||||
|
int _height = 0;
|
||||||
|
|
||||||
|
rpl::event_stream<float64> _changing;
|
||||||
|
rpl::event_stream<float64> _changed;
|
||||||
|
rpl::event_stream<float64> _debounced;
|
||||||
|
base::Timer _debounceTimer;
|
||||||
|
rpl::variable<float64> _last = 0.;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
SpeedSliderItem::SpeedSliderItem(
|
||||||
|
not_null<RpWidget*> parent,
|
||||||
|
const style::MediaSpeedMenu &st,
|
||||||
|
rpl::producer<float64> value)
|
||||||
|
: Ui::Menu::ItemBase(parent, st.menu)
|
||||||
|
, _slider(base::make_unique_q<Ui::MediaSlider>(this, st.slider))
|
||||||
|
, _dummyAction(new QAction(parent))
|
||||||
|
, _st(st)
|
||||||
|
, _height(st.sliderPadding.top()
|
||||||
|
+ st.menu.itemStyle.font->height
|
||||||
|
+ st.sliderPadding.bottom())
|
||||||
|
, _debounceTimer([=] { _debounced.fire(current()); }) {
|
||||||
|
initResizeHook(parent->sizeValue());
|
||||||
|
enableMouseSelecting();
|
||||||
|
enableMouseSelecting(_slider.get());
|
||||||
|
|
||||||
|
setMinWidth(st.sliderPadding.left()
|
||||||
|
+ st.sliderWidth
|
||||||
|
+ st.sliderPadding.right());
|
||||||
|
_slider->setAlwaysDisplayMarker(true);
|
||||||
|
|
||||||
|
sizeValue(
|
||||||
|
) | rpl::start_with_next([=](const QSize &size) {
|
||||||
|
const auto geometry = QRect(QPoint(), size);
|
||||||
|
const auto padding = _st.sliderPadding;
|
||||||
|
const auto inner = geometry - padding;
|
||||||
|
_slider->setGeometry(
|
||||||
|
padding.left(),
|
||||||
|
inner.y(),
|
||||||
|
(geometry.width() - padding.left() - padding.right()),
|
||||||
|
inner.height());
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
paintRequest(
|
||||||
|
) | rpl::start_with_next([=](const QRect &clip) {
|
||||||
|
auto p = Painter(this);
|
||||||
|
|
||||||
|
p.fillRect(clip, _st.menu.itemBg);
|
||||||
|
|
||||||
|
const auto left = (_st.sliderPadding.left() - _text.maxWidth()) / 2;
|
||||||
|
const auto top = _st.menu.itemPadding.top();
|
||||||
|
p.setPen(_st.menu.itemFg);
|
||||||
|
_text.drawLeftElided(p, left, top, _text.maxWidth(), width());
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_slider->setChangeProgressCallback([=](float64 value) {
|
||||||
|
const auto speed = SliderValueToSpeed(value);
|
||||||
|
if (current() != speed) {
|
||||||
|
_last = speed;
|
||||||
|
_changing.fire_copy(speed);
|
||||||
|
_debounceTimer.callOnce(kSpeedDebounceTimeout);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_slider->setChangeFinishedCallback([=](float64 value) {
|
||||||
|
const auto speed = SliderValueToSpeed(value);
|
||||||
|
_last = speed;
|
||||||
|
_changed.fire_copy(speed);
|
||||||
|
_debounced.fire_copy(speed);
|
||||||
|
_debounceTimer.cancel();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
value
|
||||||
|
) | rpl::start_with_next([=](float64 external) {
|
||||||
|
setExternalValue(external);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_last.value(
|
||||||
|
) | rpl::start_with_next([=](float64 value) {
|
||||||
|
const auto text = QString::number(value, 'f', 1) + 'x';
|
||||||
|
if (_text.toString() != text) {
|
||||||
|
_text.setText(_st.sliderStyle, text);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
_slider->setAdjustCallback([=](float64 value) {
|
||||||
|
const auto speed = SliderValueToSpeed(value);
|
||||||
|
for (const auto &snap : kSpeedStickedValues) {
|
||||||
|
if (speed > (snap.first - snap.second)
|
||||||
|
&& speed < (snap.first + snap.second)) {
|
||||||
|
return SpeedToSliderValue(snap.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedSliderItem::setExternalValue(float64 speed) {
|
||||||
|
if (!_slider->isChanging()) {
|
||||||
|
setSliderValue(speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedSliderItem::setSliderValue(float64 speed) {
|
||||||
|
const auto value = SpeedToSliderValue(speed);
|
||||||
|
_slider->setValue(value);
|
||||||
|
_last = speed;
|
||||||
|
_changed.fire_copy(speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
not_null<QAction*> SpeedSliderItem::action() const {
|
||||||
|
return _dummyAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpeedSliderItem::isEnabled() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SpeedSliderItem::contentHeight() const {
|
||||||
|
return _height;
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 SpeedSliderItem::current() const {
|
||||||
|
return _last.current();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<float64> SpeedSliderItem::changing() const {
|
||||||
|
return _changing.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<float64> SpeedSliderItem::changed() const {
|
||||||
|
return _changed.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<float64> SpeedSliderItem::debouncedChanges() const {
|
||||||
|
return _debounced.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Dropdown::Dropdown(QWidget *parent)
|
Dropdown::Dropdown(QWidget *parent)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
|
@ -178,4 +379,109 @@ bool Dropdown::eventFilter(QObject *obj, QEvent *e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FillSpeedMenu(
|
||||||
|
not_null<Ui::Menu::Menu*> menu,
|
||||||
|
const style::MediaSpeedMenu &st,
|
||||||
|
rpl::producer<float64> value,
|
||||||
|
Fn<void(float64)> callback) {
|
||||||
|
auto slider = base::make_unique_q<SpeedSliderItem>(
|
||||||
|
menu,
|
||||||
|
st,
|
||||||
|
rpl::duplicate(value));
|
||||||
|
|
||||||
|
slider->debouncedChanges(
|
||||||
|
) | rpl::start_with_next(callback, slider->lifetime());
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
rpl::variable<float64> realtime;
|
||||||
|
};
|
||||||
|
const auto state = slider->lifetime().make_state<State>();
|
||||||
|
state->realtime = rpl::single(
|
||||||
|
slider->current()
|
||||||
|
) | rpl::then(rpl::merge(
|
||||||
|
slider->changing(),
|
||||||
|
slider->changed()
|
||||||
|
));
|
||||||
|
|
||||||
|
menu->addAction(std::move(slider));
|
||||||
|
menu->addSeparator(&st.menu.separator);
|
||||||
|
|
||||||
|
struct SpeedPoint {
|
||||||
|
float64 speed = 0.;
|
||||||
|
tr::phrase<> text;
|
||||||
|
const style::icon &icon;
|
||||||
|
const style::icon &iconActive;
|
||||||
|
};
|
||||||
|
const auto points = std::vector<SpeedPoint>{
|
||||||
|
{
|
||||||
|
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<Ui::Menu::Action>(
|
||||||
|
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<Ui::RpWidget>(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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Media::Player
|
} // namespace Media::Player
|
||||||
|
|
|
@ -11,6 +11,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/animations.h"
|
#include "ui/effects/animations.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
|
||||||
|
namespace style {
|
||||||
|
struct MediaSpeedMenu;
|
||||||
|
} // namespace style
|
||||||
|
|
||||||
|
namespace Ui::Menu {
|
||||||
|
class Menu;
|
||||||
|
} // namespace Ui::Menu
|
||||||
|
|
||||||
namespace Media::Player {
|
namespace Media::Player {
|
||||||
|
|
||||||
class Dropdown final : public Ui::RpWidget {
|
class Dropdown final : public Ui::RpWidget {
|
||||||
|
@ -49,4 +57,10 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void FillSpeedMenu(
|
||||||
|
not_null<Ui::Menu::Menu*> menu,
|
||||||
|
const style::MediaSpeedMenu &st,
|
||||||
|
rpl::producer<float64> value,
|
||||||
|
Fn<void(float64)> callback);
|
||||||
|
|
||||||
} // namespace Media::Player
|
} // namespace Media::Player
|
||||||
|
|
|
@ -31,12 +31,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "media/player/media_player_dropdown.h"
|
#include "media/player/media_player_dropdown.h"
|
||||||
#include "media/player/media_player_volume_controller.h"
|
#include "media/player/media_player_volume_controller.h"
|
||||||
#include "styles/style_media_player.h"
|
|
||||||
#include "styles/style_media_view.h"
|
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history_item_helpers.h"
|
#include "history/history_item_helpers.h"
|
||||||
#include "storage/storage_account.h"
|
#include "storage/storage_account.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
|
#include "styles/style_media_player.h"
|
||||||
|
#include "styles/style_media_view.h"
|
||||||
|
#include "styles/style_chat.h" // expandedMenuSeparator.
|
||||||
|
|
||||||
namespace Media {
|
namespace Media {
|
||||||
namespace Player {
|
namespace Player {
|
||||||
|
@ -44,12 +45,12 @@ namespace Player {
|
||||||
class WithDropdownController {
|
class WithDropdownController {
|
||||||
public:
|
public:
|
||||||
WithDropdownController(
|
WithDropdownController(
|
||||||
not_null<Ui::IconButton*> button,
|
not_null<Ui::AbstractButton*> button,
|
||||||
not_null<Ui::RpWidget*> menuParent,
|
not_null<Ui::RpWidget*> menuParent,
|
||||||
Fn<void(bool)> menuOverCallback);
|
Fn<void(bool)> menuOverCallback);
|
||||||
virtual ~WithDropdownController() = default;
|
virtual ~WithDropdownController() = default;
|
||||||
|
|
||||||
[[nodiscard]] not_null<Ui::IconButton*> button() const;
|
[[nodiscard]] not_null<Ui::AbstractButton*> button() const;
|
||||||
Ui::DropdownMenu *menu() const;
|
Ui::DropdownMenu *menu() const;
|
||||||
|
|
||||||
void updateDropdownGeometry();
|
void updateDropdownGeometry();
|
||||||
|
@ -63,7 +64,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
virtual void fillMenu(not_null<Ui::DropdownMenu*> menu) = 0;
|
virtual void fillMenu(not_null<Ui::DropdownMenu*> menu) = 0;
|
||||||
|
|
||||||
const not_null<Ui::IconButton*> _button;
|
const not_null<Ui::AbstractButton*> _button;
|
||||||
const not_null<Ui::RpWidget*> _menuParent;
|
const not_null<Ui::RpWidget*> _menuParent;
|
||||||
const Fn<void(bool)> _menuOverCallback;
|
const Fn<void(bool)> _menuOverCallback;
|
||||||
base::unique_qptr<Ui::DropdownMenu> _menu;
|
base::unique_qptr<Ui::DropdownMenu> _menu;
|
||||||
|
@ -72,6 +73,24 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
QImage prepareRippleMask() const override;
|
||||||
|
QPoint prepareRippleStartPosition() const override;
|
||||||
|
|
||||||
|
SpeedButtonLayout _layout;
|
||||||
|
QPoint _layoutPosition;
|
||||||
|
bool _isDefault = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class Widget::OrderController final : public WithDropdownController {
|
class Widget::OrderController final : public WithDropdownController {
|
||||||
public:
|
public:
|
||||||
OrderController(
|
OrderController(
|
||||||
|
@ -83,12 +102,14 @@ private:
|
||||||
void fillMenu(not_null<Ui::DropdownMenu*> menu) override;
|
void fillMenu(not_null<Ui::DropdownMenu*> menu) override;
|
||||||
void updateIcon();
|
void updateIcon();
|
||||||
|
|
||||||
|
const not_null<Ui::IconButton*> _button;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Widget::SpeedController final : public WithDropdownController {
|
class Widget::SpeedController final : public WithDropdownController {
|
||||||
public:
|
public:
|
||||||
SpeedController(
|
SpeedController(
|
||||||
not_null<Ui::IconButton*> button,
|
not_null<SpeedButton*> button,
|
||||||
not_null<Ui::RpWidget*> menuParent,
|
not_null<Ui::RpWidget*> menuParent,
|
||||||
Fn<void(bool)> menuOverCallback);
|
Fn<void(bool)> menuOverCallback);
|
||||||
|
|
||||||
|
@ -96,7 +117,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void fillMenu(not_null<Ui::DropdownMenu*> menu) override;
|
void fillMenu(not_null<Ui::DropdownMenu*> menu) override;
|
||||||
void updateIcon();
|
|
||||||
|
|
||||||
[[nodiscard]] float64 speed() const;
|
[[nodiscard]] float64 speed() const;
|
||||||
[[nodiscard]] bool isDefault() const;
|
[[nodiscard]] bool isDefault() const;
|
||||||
|
@ -105,7 +125,7 @@ private:
|
||||||
void setSpeed(float64 newSpeed);
|
void setSpeed(float64 newSpeed);
|
||||||
void save();
|
void save();
|
||||||
|
|
||||||
float64 _speed = 2.;
|
float64 _speed = 1.7;
|
||||||
bool _isDefault = true;
|
bool _isDefault = true;
|
||||||
rpl::event_stream<float64> _speedChanged;
|
rpl::event_stream<float64> _speedChanged;
|
||||||
rpl::event_stream<> _saved;
|
rpl::event_stream<> _saved;
|
||||||
|
@ -113,7 +133,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
WithDropdownController::WithDropdownController(
|
WithDropdownController::WithDropdownController(
|
||||||
not_null<Ui::IconButton*> button,
|
not_null<Ui::AbstractButton*> button,
|
||||||
not_null<Ui::RpWidget*> menuParent,
|
not_null<Ui::RpWidget*> menuParent,
|
||||||
Fn<void(bool)> menuOverCallback)
|
Fn<void(bool)> menuOverCallback)
|
||||||
: _button(button)
|
: _button(button)
|
||||||
|
@ -135,7 +155,7 @@ WithDropdownController::WithDropdownController(
|
||||||
}, button->lifetime());
|
}, button->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
not_null<Ui::IconButton*> WithDropdownController::button() const {
|
not_null<Ui::AbstractButton*> WithDropdownController::button() const {
|
||||||
return _button;
|
return _button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,11 +219,48 @@ void WithDropdownController::showMenu() {
|
||||||
_menu->showAnimated(Ui::PanelAnimation::Origin::TopRight);
|
_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);
|
||||||
|
|
||||||
|
paintRipple(
|
||||||
|
p,
|
||||||
|
QPoint(),
|
||||||
|
_isDefault ? &st::mediaPlayerSpeedDisabledRippleBg->c : nullptr);
|
||||||
|
|
||||||
|
const auto &color = !_isDefault
|
||||||
|
? st::mediaPlayerActiveFg
|
||||||
|
: isOver()
|
||||||
|
? st::menuIconFgOver
|
||||||
|
: st::menuIconFg;
|
||||||
|
p.translate(_layoutPosition);
|
||||||
|
_layout.paint(p, color->c);
|
||||||
|
}
|
||||||
|
|
||||||
Widget::OrderController::OrderController(
|
Widget::OrderController::OrderController(
|
||||||
not_null<Ui::IconButton*> button,
|
not_null<Ui::IconButton*> button,
|
||||||
not_null<Ui::RpWidget*> menuParent,
|
not_null<Ui::RpWidget*> menuParent,
|
||||||
Fn<void(bool)> menuOverCallback)
|
Fn<void(bool)> menuOverCallback)
|
||||||
: WithDropdownController(button, menuParent, std::move(menuOverCallback)) {
|
: WithDropdownController(button, menuParent, std::move(menuOverCallback))
|
||||||
|
, _button(button) {
|
||||||
button->setClickedCallback([=] {
|
button->setClickedCallback([=] {
|
||||||
showMenu();
|
showMenu();
|
||||||
});
|
});
|
||||||
|
@ -260,25 +317,25 @@ void Widget::OrderController::fillMenu(not_null<Ui::DropdownMenu*> menu) {
|
||||||
void Widget::OrderController::updateIcon() {
|
void Widget::OrderController::updateIcon() {
|
||||||
switch (Core::App().settings().playerOrderMode()) {
|
switch (Core::App().settings().playerOrderMode()) {
|
||||||
case OrderMode::Default:
|
case OrderMode::Default:
|
||||||
button()->setIconOverride(
|
_button->setIconOverride(
|
||||||
&st::mediaPlayerReverseDisabledIcon,
|
&st::mediaPlayerReverseDisabledIcon,
|
||||||
&st::mediaPlayerReverseDisabledIconOver);
|
&st::mediaPlayerReverseDisabledIconOver);
|
||||||
button()->setRippleColorOverride(
|
_button->setRippleColorOverride(
|
||||||
&st::mediaPlayerRepeatDisabledRippleBg);
|
&st::mediaPlayerRepeatDisabledRippleBg);
|
||||||
break;
|
break;
|
||||||
case OrderMode::Reverse:
|
case OrderMode::Reverse:
|
||||||
button()->setIconOverride(&st::mediaPlayerReverseIcon);
|
_button->setIconOverride(&st::mediaPlayerReverseIcon);
|
||||||
button()->setRippleColorOverride(nullptr);
|
_button->setRippleColorOverride(nullptr);
|
||||||
break;
|
break;
|
||||||
case OrderMode::Shuffle:
|
case OrderMode::Shuffle:
|
||||||
button()->setIconOverride(&st::mediaPlayerShuffleIcon);
|
_button->setIconOverride(&st::mediaPlayerShuffleIcon);
|
||||||
button()->setRippleColorOverride(nullptr);
|
_button->setRippleColorOverride(nullptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget::SpeedController::SpeedController(
|
Widget::SpeedController::SpeedController(
|
||||||
not_null<Ui::IconButton*> button,
|
not_null<SpeedButton*> button,
|
||||||
not_null<Ui::RpWidget*> menuParent,
|
not_null<Ui::RpWidget*> menuParent,
|
||||||
Fn<void(bool)> menuOverCallback)
|
Fn<void(bool)> menuOverCallback)
|
||||||
: WithDropdownController(button, menuParent, std::move(menuOverCallback)) {
|
: WithDropdownController(button, menuParent, std::move(menuOverCallback)) {
|
||||||
|
@ -293,45 +350,15 @@ Widget::SpeedController::SpeedController(
|
||||||
setSpeed(Core::App().settings().voicePlaybackSpeed());
|
setSpeed(Core::App().settings().voicePlaybackSpeed());
|
||||||
_speed = Core::App().settings().voicePlaybackSpeed(true);
|
_speed = Core::App().settings().voicePlaybackSpeed(true);
|
||||||
|
|
||||||
|
button->setSpeed(_speed, anim::type::instant);
|
||||||
|
|
||||||
_speedChanged.events_starting_with(
|
_speedChanged.events_starting_with(
|
||||||
speed()
|
speed()
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=](float64 speed) {
|
||||||
updateIcon();
|
button->setSpeed(speed);
|
||||||
}, button->lifetime());
|
}, button->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::SpeedController::updateIcon() {
|
|
||||||
const auto isDefaultSpeed = isDefault();
|
|
||||||
const auto nonDefaultSpeed = lastNonDefaultSpeed();
|
|
||||||
|
|
||||||
if (nonDefaultSpeed == .5) {
|
|
||||||
button()->setIconOverride(
|
|
||||||
(isDefaultSpeed
|
|
||||||
? &st::mediaPlayerSpeedSlowDisabledIcon
|
|
||||||
: &st::mediaPlayerSpeedSlowIcon),
|
|
||||||
(isDefaultSpeed
|
|
||||||
? &st::mediaPlayerSpeedSlowDisabledIconOver
|
|
||||||
: &st::mediaPlayerSpeedSlowIcon));
|
|
||||||
} else if (nonDefaultSpeed == 1.5) {
|
|
||||||
button()->setIconOverride(
|
|
||||||
(isDefaultSpeed
|
|
||||||
? &st::mediaPlayerSpeedFastDisabledIcon
|
|
||||||
: &st::mediaPlayerSpeedFastIcon),
|
|
||||||
(isDefaultSpeed
|
|
||||||
? &st::mediaPlayerSpeedFastDisabledIconOver
|
|
||||||
: &st::mediaPlayerSpeedFastIcon));
|
|
||||||
} else {
|
|
||||||
button()->setIconOverride(
|
|
||||||
isDefaultSpeed ? &st::mediaPlayerSpeedDisabledIcon : nullptr,
|
|
||||||
(isDefaultSpeed
|
|
||||||
? &st::mediaPlayerSpeedDisabledIconOver
|
|
||||||
: nullptr));
|
|
||||||
}
|
|
||||||
button()->setRippleColorOverride(isDefaultSpeed
|
|
||||||
? &st::mediaPlayerSpeedDisabledRippleBg
|
|
||||||
: nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<> Widget::SpeedController::saved() const {
|
rpl::producer<> Widget::SpeedController::saved() const {
|
||||||
return _saved.events();
|
return _saved.events();
|
||||||
}
|
}
|
||||||
|
@ -367,35 +394,11 @@ void Widget::SpeedController::save() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::SpeedController::fillMenu(not_null<Ui::DropdownMenu*> menu) {
|
void Widget::SpeedController::fillMenu(not_null<Ui::DropdownMenu*> menu) {
|
||||||
const auto currentSpeed = speed();
|
FillSpeedMenu(
|
||||||
const auto addSpeedAction = [&](float64 speed, QString text) {
|
menu->menu(),
|
||||||
const auto callback = [=] {
|
st::mediaSpeedMenu,
|
||||||
setSpeed(speed);
|
_speedChanged.events_starting_with(speed()),
|
||||||
save();
|
[=](float64 speed) { setSpeed(speed); save(); });
|
||||||
};
|
|
||||||
const auto icon = (speed == currentSpeed)
|
|
||||||
? &st::mediaPlayerMenuCheck
|
|
||||||
: nullptr;
|
|
||||||
auto action = base::make_unique_q<Ui::Menu::Action>(
|
|
||||||
menu,
|
|
||||||
st::mediaPlayerSpeedMenu,
|
|
||||||
Ui::Menu::CreateAction(menu, text, callback),
|
|
||||||
icon,
|
|
||||||
icon);
|
|
||||||
const auto raw = action.get();
|
|
||||||
_speedChanged.events(
|
|
||||||
) | rpl::start_with_next([=](float64 updatedSpeed) {
|
|
||||||
const auto icon = (speed == updatedSpeed)
|
|
||||||
? &st::mediaPlayerMenuCheck
|
|
||||||
: nullptr;
|
|
||||||
raw->setIcon(icon, icon);
|
|
||||||
}, raw->lifetime());
|
|
||||||
menu->addAction(std::move(action));
|
|
||||||
};
|
|
||||||
addSpeedAction(0.5, tr::lng_voice_speed_slow(tr::now));
|
|
||||||
addSpeedAction(1., tr::lng_voice_speed_normal(tr::now));
|
|
||||||
addSpeedAction(1.5, tr::lng_voice_speed_fast(tr::now));
|
|
||||||
addSpeedAction(2., tr::lng_voice_speed_very_fast(tr::now));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget::Widget(
|
Widget::Widget(
|
||||||
|
@ -412,7 +415,7 @@ Widget::Widget(
|
||||||
, _volumeToggle(rightControls(), st::mediaPlayerVolumeToggle)
|
, _volumeToggle(rightControls(), st::mediaPlayerVolumeToggle)
|
||||||
, _repeatToggle(rightControls(), st::mediaPlayerRepeatButton)
|
, _repeatToggle(rightControls(), st::mediaPlayerRepeatButton)
|
||||||
, _orderToggle(rightControls(), st::mediaPlayerRepeatButton)
|
, _orderToggle(rightControls(), st::mediaPlayerRepeatButton)
|
||||||
, _speedToggle(rightControls(), st::mediaPlayerSpeedButton)
|
, _speedToggle(rightControls())
|
||||||
, _close(this, st::mediaPlayerClose)
|
, _close(this, st::mediaPlayerClose)
|
||||||
, _shadow(this)
|
, _shadow(this)
|
||||||
, _playbackSlider(this, st::mediaPlayerPlayback)
|
, _playbackSlider(this, st::mediaPlayerPlayback)
|
||||||
|
|
|
@ -23,21 +23,16 @@ template <typename Widget>
|
||||||
class FadeWrap;
|
class FadeWrap;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Media {
|
namespace Media::View {
|
||||||
namespace View {
|
|
||||||
class PlaybackProgress;
|
class PlaybackProgress;
|
||||||
} // namespace Clip
|
} // namespace Media::View
|
||||||
} // namespace Media
|
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
class SessionController;
|
class SessionController;
|
||||||
} // namespace Window
|
} // namespace Window
|
||||||
|
|
||||||
namespace Media {
|
namespace Media::Player {
|
||||||
namespace Player {
|
|
||||||
|
|
||||||
class PlayButton;
|
|
||||||
class SpeedButton;
|
|
||||||
class Dropdown;
|
class Dropdown;
|
||||||
struct TrackState;
|
struct TrackState;
|
||||||
|
|
||||||
|
@ -47,6 +42,7 @@ public:
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
not_null<Ui::RpWidget*> dropdownsParent,
|
not_null<Ui::RpWidget*> dropdownsParent,
|
||||||
not_null<Window::SessionController*> controller);
|
not_null<Window::SessionController*> controller);
|
||||||
|
~Widget();
|
||||||
|
|
||||||
void setCloseCallback(Fn<void()> callback);
|
void setCloseCallback(Fn<void()> callback);
|
||||||
void setShowItemCallback(Fn<void(not_null<const HistoryItem*>)> callback);
|
void setShowItemCallback(Fn<void(not_null<const HistoryItem*>)> callback);
|
||||||
|
@ -61,8 +57,6 @@ public:
|
||||||
return _togglePlaylistRequests.events();
|
return _togglePlaylistRequests.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Widget();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
@ -134,7 +128,7 @@ private:
|
||||||
bool _wontBeOver = false;
|
bool _wontBeOver = false;
|
||||||
bool _volumeHidden = false;
|
bool _volumeHidden = false;
|
||||||
|
|
||||||
class PlayButton;
|
class SpeedButton;
|
||||||
class OrderController;
|
class OrderController;
|
||||||
class SpeedController;
|
class SpeedController;
|
||||||
object_ptr<Ui::FlatLabel> _nameLabel;
|
object_ptr<Ui::FlatLabel> _nameLabel;
|
||||||
|
@ -146,7 +140,7 @@ private:
|
||||||
object_ptr<Ui::IconButton> _volumeToggle;
|
object_ptr<Ui::IconButton> _volumeToggle;
|
||||||
object_ptr<Ui::IconButton> _repeatToggle;
|
object_ptr<Ui::IconButton> _repeatToggle;
|
||||||
object_ptr<Ui::IconButton> _orderToggle;
|
object_ptr<Ui::IconButton> _orderToggle;
|
||||||
object_ptr<Ui::IconButton> _speedToggle;
|
object_ptr<SpeedButton> _speedToggle;
|
||||||
object_ptr<Ui::IconButton> _close;
|
object_ptr<Ui::IconButton> _close;
|
||||||
object_ptr<Ui::PlainShadow> _shadow = { nullptr };
|
object_ptr<Ui::PlainShadow> _shadow = { nullptr };
|
||||||
object_ptr<Ui::FilledSlider> _playbackSlider;
|
object_ptr<Ui::FilledSlider> _playbackSlider;
|
||||||
|
@ -159,5 +153,4 @@ private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Player
|
} // namespace Media::Player
|
||||||
} // namespace Media
|
|
||||||
|
|
|
@ -528,7 +528,8 @@ void Player::fail(Error error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::play(const PlaybackOptions &options) {
|
void Player::play(const PlaybackOptions &options) {
|
||||||
Expects(options.speed >= 0.5 && options.speed <= 2.);
|
Expects(options.speed >= Audio::kSpeedMin
|
||||||
|
&& options.speed <= Audio::kSpeedMax);
|
||||||
|
|
||||||
// Looping video with audio is not supported for now.
|
// Looping video with audio is not supported for now.
|
||||||
Expects(!options.loop || (options.mode != Mode::Both));
|
Expects(!options.loop || (options.mode != Mode::Both));
|
||||||
|
@ -828,7 +829,7 @@ float64 Player::speed() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::setSpeed(float64 speed) {
|
void Player::setSpeed(float64 speed) {
|
||||||
Expects(speed >= 0.5 && speed <= 2.);
|
Expects(speed >= Audio::kSpeedMin && speed <= Audio::kSpeedMax);
|
||||||
|
|
||||||
if (!Media::Audio::SupportsSpeedControl()) {
|
if (!Media::Audio::SupportsSpeedControl()) {
|
||||||
speed = 1.;
|
speed = 1.;
|
||||||
|
|
|
@ -1093,9 +1093,6 @@ void Pip::handleMousePress(QPoint position, Qt::MouseButton button) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
|
void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
|
||||||
Expects(1 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
const auto weak = Ui::MakeWeak(_panel.widget());
|
const auto weak = Ui::MakeWeak(_panel.widget());
|
||||||
const auto guard = gsl::finally([&] {
|
const auto guard = gsl::finally([&] {
|
||||||
if (weak) {
|
if (weak) {
|
||||||
|
@ -1107,21 +1104,11 @@ void Pip::handleMouseRelease(QPoint position, Qt::MouseButton button) {
|
||||||
}
|
}
|
||||||
seekUpdate(position);
|
seekUpdate(position);
|
||||||
|
|
||||||
Assert(2 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
volumeControllerUpdate(position);
|
volumeControllerUpdate(position);
|
||||||
|
|
||||||
Assert(3 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
const auto pressed = base::take(_pressed);
|
const auto pressed = base::take(_pressed);
|
||||||
if (pressed && *pressed == OverState::Playback) {
|
if (pressed && *pressed == OverState::Playback) {
|
||||||
_panel.setDragDisabled(false);
|
_panel.setDragDisabled(false);
|
||||||
|
|
||||||
Assert(4 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
seekFinish(_playbackProgress->value());
|
seekFinish(_playbackProgress->value());
|
||||||
} else if (pressed && *pressed == OverState::VolumeController) {
|
} else if (pressed && *pressed == OverState::VolumeController) {
|
||||||
_panel.setDragDisabled(false);
|
_panel.setDragDisabled(false);
|
||||||
|
@ -1182,9 +1169,6 @@ void Pip::seekProgress(float64 value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pip::seekFinish(float64 value) {
|
void Pip::seekFinish(float64 value) {
|
||||||
Expects(5 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
if (!_lastDurationMs) {
|
if (!_lastDurationMs) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1671,31 +1655,18 @@ void Pip::playbackPauseResume() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pip::restartAtSeekPosition(crl::time position) {
|
void Pip::restartAtSeekPosition(crl::time position) {
|
||||||
Expects(6 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
if (!_instance.info().video.cover.isNull()) {
|
if (!_instance.info().video.cover.isNull()) {
|
||||||
_preparedCoverStorage = QImage();
|
_preparedCoverStorage = QImage();
|
||||||
_preparedCoverState = ThumbState::Empty;
|
_preparedCoverState = ThumbState::Empty;
|
||||||
_instance.saveFrameToCover();
|
_instance.saveFrameToCover();
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(7 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
auto options = Streaming::PlaybackOptions();
|
auto options = Streaming::PlaybackOptions();
|
||||||
options.position = position;
|
options.position = position;
|
||||||
options.hwAllowed = Core::App().settings().hardwareAcceleratedVideo();
|
options.hwAllowed = Core::App().settings().hardwareAcceleratedVideo();
|
||||||
options.audioId = _instance.player().prepareLegacyState().id;
|
options.audioId = _instance.player().prepareLegacyState().id;
|
||||||
|
|
||||||
Assert(8 && _delegate->pipPlaybackSpeed() >= 0.5
|
|
||||||
&& _delegate->pipPlaybackSpeed() <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
options.speed = _delegate->pipPlaybackSpeed();
|
options.speed = _delegate->pipPlaybackSpeed();
|
||||||
|
|
||||||
Assert(9 && options.speed >= 0.5
|
|
||||||
&& options.speed <= 2.); // Debugging strange crash.
|
|
||||||
|
|
||||||
_instance.play(options);
|
_instance.play(options);
|
||||||
if (_startPaused) {
|
if (_startPaused) {
|
||||||
_instance.pause();
|
_instance.pause();
|
||||||
|
|
|
@ -120,6 +120,8 @@ PRIVATE
|
||||||
media/clip/media_clip_reader.cpp
|
media/clip/media_clip_reader.cpp
|
||||||
media/clip/media_clip_reader.h
|
media/clip/media_clip_reader.h
|
||||||
|
|
||||||
|
media/player/media_player_button.cpp
|
||||||
|
media/player/media_player_button.h
|
||||||
media/player/media_player_dropdown.cpp
|
media/player/media_player_dropdown.cpp
|
||||||
media/player/media_player_dropdown.h
|
media/player/media_player_dropdown.h
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit c80df2cdd2d2838d5e4aab50075e4f6e7c05e380
|
Subproject commit 62a62d1fb5abe9dc1e6b9f89af1ccef6fef33c52
|