Add a second dropdown with playback mode controls.
|
@ -813,6 +813,8 @@ PRIVATE
|
||||||
media/player/media_player_instance.h
|
media/player/media_player_instance.h
|
||||||
media/player/media_player_panel.cpp
|
media/player/media_player_panel.cpp
|
||||||
media/player/media_player_panel.h
|
media/player/media_player_panel.h
|
||||||
|
media/player/media_player_repeat_controls.cpp
|
||||||
|
media/player/media_player_repeat_controls.h
|
||||||
media/player/media_player_volume_controller.cpp
|
media/player/media_player_volume_controller.cpp
|
||||||
media/player/media_player_volume_controller.h
|
media/player/media_player_volume_controller.h
|
||||||
media/player/media_player_widget.cpp
|
media/player/media_player_widget.cpp
|
||||||
|
|
BIN
Telegram/Resources/icons/player/player_repeat_one.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
Telegram/Resources/icons/player/player_repeat_one@2x.png
Normal file
After Width: | Height: | Size: 304 B |
BIN
Telegram/Resources/icons/player/player_repeat_one@3x.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
Telegram/Resources/icons/player/player_repeat_reverse.png
Normal file
After Width: | Height: | Size: 246 B |
BIN
Telegram/Resources/icons/player/player_repeat_reverse@2x.png
Normal file
After Width: | Height: | Size: 301 B |
BIN
Telegram/Resources/icons/player/player_repeat_reverse@3x.png
Normal file
After Width: | Height: | Size: 371 B |
BIN
Telegram/Resources/icons/player/player_repeat_shuffle.png
Normal file
After Width: | Height: | Size: 269 B |
BIN
Telegram/Resources/icons/player/player_repeat_shuffle@2x.png
Normal file
After Width: | Height: | Size: 290 B |
BIN
Telegram/Resources/icons/player/player_repeat_shuffle@3x.png
Normal file
After Width: | Height: | Size: 387 B |
BIN
Telegram/Resources/icons/player/player_reverse.png
Normal file
After Width: | Height: | Size: 198 B |
BIN
Telegram/Resources/icons/player/player_reverse@2x.png
Normal file
After Width: | Height: | Size: 212 B |
BIN
Telegram/Resources/icons/player/player_reverse@3x.png
Normal file
After Width: | Height: | Size: 298 B |
BIN
Telegram/Resources/icons/player/player_shuffle.png
Normal file
After Width: | Height: | Size: 346 B |
BIN
Telegram/Resources/icons/player/player_shuffle@2x.png
Normal file
After Width: | Height: | Size: 537 B |
BIN
Telegram/Resources/icons/player/player_shuffle@3x.png
Normal file
After Width: | Height: | Size: 761 B |
|
@ -81,6 +81,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "media/player/media_player_panel.h"
|
#include "media/player/media_player_panel.h"
|
||||||
#include "media/player/media_player_widget.h"
|
#include "media/player/media_player_widget.h"
|
||||||
#include "media/player/media_player_dropdown.h"
|
#include "media/player/media_player_dropdown.h"
|
||||||
|
#include "media/player/media_player_repeat_controls.h"
|
||||||
#include "media/player/media_player_volume_controller.h"
|
#include "media/player/media_player_volume_controller.h"
|
||||||
#include "media/player/media_player_instance.h"
|
#include "media/player/media_player_instance.h"
|
||||||
#include "media/player/media_player_float.h"
|
#include "media/player/media_player_float.h"
|
||||||
|
@ -813,6 +814,7 @@ void MainWidget::closeBothPlayers() {
|
||||||
_player->hide(anim::type::normal);
|
_player->hide(anim::type::normal);
|
||||||
}
|
}
|
||||||
_playerVolume.destroyDelayed();
|
_playerVolume.destroyDelayed();
|
||||||
|
_playerRepeat.destroyDelayed();
|
||||||
|
|
||||||
_playerPlaylist->hideIgnoringEnterEvents();
|
_playerPlaylist->hideIgnoringEnterEvents();
|
||||||
Media::Player::instance()->stop(AudioMsgId::Type::Voice);
|
Media::Player::instance()->stop(AudioMsgId::Type::Voice);
|
||||||
|
@ -849,6 +851,11 @@ void MainWidget::createPlayer() {
|
||||||
_playerVolume.data(),
|
_playerVolume.data(),
|
||||||
_controller);
|
_controller);
|
||||||
_player->entity()->volumeWidgetCreated(_playerVolume);
|
_player->entity()->volumeWidgetCreated(_playerVolume);
|
||||||
|
_playerRepeat.create(this);
|
||||||
|
Media::Player::PrepareRepeatDropdown(
|
||||||
|
_playerRepeat.data(),
|
||||||
|
_controller);
|
||||||
|
_player->entity()->repeatWidgetCreated(_playerRepeat);
|
||||||
orderWidgets();
|
orderWidgets();
|
||||||
if (_a_show.animating()) {
|
if (_a_show.animating()) {
|
||||||
_player->show(anim::type::instant);
|
_player->show(anim::type::instant);
|
||||||
|
@ -883,6 +890,7 @@ void MainWidget::playerHeightUpdated() {
|
||||||
const auto state = Media::Player::instance()->getState(Media::Player::instance()->getActiveType());
|
const auto state = Media::Player::instance()->getState(Media::Player::instance()->getActiveType());
|
||||||
if (!state.id || Media::Player::IsStoppedOrStopping(state.state)) {
|
if (!state.id || Media::Player::IsStoppedOrStopping(state.state)) {
|
||||||
_playerVolume.destroyDelayed();
|
_playerVolume.destroyDelayed();
|
||||||
|
_playerRepeat.destroyDelayed();
|
||||||
_player.destroyDelayed();
|
_player.destroyDelayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1536,6 +1544,10 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(
|
||||||
if (playerVolumeVisible) {
|
if (playerVolumeVisible) {
|
||||||
_playerVolume->hide();
|
_playerVolume->hide();
|
||||||
}
|
}
|
||||||
|
auto playerRepeatVisible = _playerRepeat && !_playerRepeat->isHidden();
|
||||||
|
if (playerRepeatVisible) {
|
||||||
|
_playerRepeat->hide();
|
||||||
|
}
|
||||||
auto playerPlaylistVisible = !_playerPlaylist->isHidden();
|
auto playerPlaylistVisible = !_playerPlaylist->isHidden();
|
||||||
if (playerPlaylistVisible) {
|
if (playerPlaylistVisible) {
|
||||||
_playerPlaylist->hide();
|
_playerPlaylist->hide();
|
||||||
|
@ -1563,6 +1575,9 @@ Window::SectionSlideParams MainWidget::prepareShowAnimation(
|
||||||
if (playerVolumeVisible) {
|
if (playerVolumeVisible) {
|
||||||
_playerVolume->show();
|
_playerVolume->show();
|
||||||
}
|
}
|
||||||
|
if (playerRepeatVisible) {
|
||||||
|
_playerRepeat->show();
|
||||||
|
}
|
||||||
if (playerPlaylistVisible) {
|
if (playerPlaylistVisible) {
|
||||||
_playerPlaylist->show();
|
_playerPlaylist->show();
|
||||||
}
|
}
|
||||||
|
@ -1822,6 +1837,9 @@ void MainWidget::orderWidgets() {
|
||||||
if (_playerVolume) {
|
if (_playerVolume) {
|
||||||
_playerVolume->raise();
|
_playerVolume->raise();
|
||||||
}
|
}
|
||||||
|
if (_playerRepeat) {
|
||||||
|
_playerRepeat->raise();
|
||||||
|
}
|
||||||
_sideShadow->raise();
|
_sideShadow->raise();
|
||||||
if (_thirdShadow) {
|
if (_thirdShadow) {
|
||||||
_thirdShadow->raise();
|
_thirdShadow->raise();
|
||||||
|
@ -1855,6 +1873,10 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶m
|
||||||
if (playerVolumeVisible) {
|
if (playerVolumeVisible) {
|
||||||
_playerVolume->hide();
|
_playerVolume->hide();
|
||||||
}
|
}
|
||||||
|
auto playerRepeatVisible = _playerRepeat && !_playerRepeat->isHidden();
|
||||||
|
if (playerRepeatVisible) {
|
||||||
|
_playerRepeat->hide();
|
||||||
|
}
|
||||||
auto playerPlaylistVisible = !_playerPlaylist->isHidden();
|
auto playerPlaylistVisible = !_playerPlaylist->isHidden();
|
||||||
if (playerPlaylistVisible) {
|
if (playerPlaylistVisible) {
|
||||||
_playerPlaylist->hide();
|
_playerPlaylist->hide();
|
||||||
|
@ -1885,6 +1907,9 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶m
|
||||||
if (playerVolumeVisible) {
|
if (playerVolumeVisible) {
|
||||||
_playerVolume->show();
|
_playerVolume->show();
|
||||||
}
|
}
|
||||||
|
if (playerRepeatVisible) {
|
||||||
|
_playerRepeat->show();
|
||||||
|
}
|
||||||
if (playerPlaylistVisible) {
|
if (playerPlaylistVisible) {
|
||||||
_playerPlaylist->show();
|
_playerPlaylist->show();
|
||||||
}
|
}
|
||||||
|
@ -2374,11 +2399,19 @@ void MainWidget::updateThirdColumnToCurrentChat(
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::updateMediaPlayerPosition() {
|
void MainWidget::updateMediaPlayerPosition() {
|
||||||
if (_player && _playerVolume) {
|
if (!_player) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_playerVolume) {
|
||||||
auto relativePosition = _player->entity()->getPositionForVolumeWidget();
|
auto relativePosition = _player->entity()->getPositionForVolumeWidget();
|
||||||
auto playerMargins = _playerVolume->getMargin();
|
auto playerMargins = _playerVolume->getMargin();
|
||||||
_playerVolume->moveToLeft(_player->x() + relativePosition.x() - playerMargins.left(), _player->y() + relativePosition.y() - playerMargins.top());
|
_playerVolume->moveToLeft(_player->x() + relativePosition.x() - playerMargins.left(), _player->y() + relativePosition.y() - playerMargins.top());
|
||||||
}
|
}
|
||||||
|
if (_playerRepeat) {
|
||||||
|
auto relativePosition = _player->entity()->getPositionForRepeatWidget();
|
||||||
|
auto playerMargins = _playerRepeat->getMargin();
|
||||||
|
_playerRepeat->moveToLeft(_player->x() + relativePosition.x() - playerMargins.left(), _player->y() + relativePosition.y() - playerMargins.top());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::updateMediaPlaylistPosition(int x) {
|
void MainWidget::updateMediaPlaylistPosition(int x) {
|
||||||
|
@ -2529,8 +2562,9 @@ void MainWidget::searchInChat(Dialogs::Key chat) {
|
||||||
|
|
||||||
bool MainWidget::contentOverlapped(const QRect &globalRect) {
|
bool MainWidget::contentOverlapped(const QRect &globalRect) {
|
||||||
return (_history->contentOverlapped(globalRect)
|
return (_history->contentOverlapped(globalRect)
|
||||||
|| _playerPlaylist->overlaps(globalRect)
|
|| _playerPlaylist->overlaps(globalRect)
|
||||||
|| (_playerVolume && _playerVolume->overlaps(globalRect)));
|
|| (_playerVolume && _playerVolume->overlaps(globalRect)))
|
||||||
|
|| (_playerRepeat && _playerRepeat->overlaps(globalRect));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::activate() {
|
void MainWidget::activate() {
|
||||||
|
|
|
@ -368,6 +368,7 @@ private:
|
||||||
object_ptr<Window::TopBarWrapWidget<Media::Player::Widget>> _player
|
object_ptr<Window::TopBarWrapWidget<Media::Player::Widget>> _player
|
||||||
= { nullptr };
|
= { nullptr };
|
||||||
object_ptr<Media::Player::Dropdown> _playerVolume = { nullptr };
|
object_ptr<Media::Player::Dropdown> _playerVolume = { nullptr };
|
||||||
|
object_ptr<Media::Player::Dropdown> _playerRepeat = { nullptr };
|
||||||
object_ptr<Media::Player::Panel> _playerPlaylist;
|
object_ptr<Media::Player::Panel> _playerPlaylist;
|
||||||
bool _playerUsingPanel = false;
|
bool _playerUsingPanel = false;
|
||||||
|
|
||||||
|
|
|
@ -67,10 +67,40 @@ mediaPlayerRepeatDisabledIcon: icon {
|
||||||
mediaPlayerRepeatDisabledIconOver: icon {
|
mediaPlayerRepeatDisabledIconOver: icon {
|
||||||
{ "player/player_repeat", menuIconFgOver, point(9px, 11px)}
|
{ "player/player_repeat", menuIconFgOver, point(9px, 11px)}
|
||||||
};
|
};
|
||||||
mediaPlayerRepeatDisabledRippleBg: windowBgOver;
|
mediaPlayerRepeatOneIcon: icon {
|
||||||
mediaPlayerRepeatInactiveIcon: icon {
|
{ "player/player_repeat_one", mediaPlayerActiveFg, point(9px, 11px)}
|
||||||
{ "player/player_repeat", mediaPlayerInactiveFg, point(9px, 11px)}
|
|
||||||
};
|
};
|
||||||
|
mediaPlayerRepeatOneDisabledIcon: icon {
|
||||||
|
{ "player/player_repeat_one", menuIconFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerRepeatOneDisabledIconOver: icon {
|
||||||
|
{ "player/player_repeat_one", menuIconFgOver, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerReverseIcon: icon {
|
||||||
|
{ "player/player_reverse", mediaPlayerActiveFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerReverseDisabledIcon: icon {
|
||||||
|
{ "player/player_reverse", menuIconFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerReverseDisabledIconOver: icon {
|
||||||
|
{ "player/player_reverse", menuIconFgOver, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerShuffleIcon: icon {
|
||||||
|
{ "player/player_shuffle", mediaPlayerActiveFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerShuffleDisabledIcon: icon {
|
||||||
|
{ "player/player_shuffle", menuIconFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerShuffleDisabledIconOver: icon {
|
||||||
|
{ "player/player_shuffle", menuIconFgOver, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerRepeatReverseIcon: icon {
|
||||||
|
{ "player/player_repeat_reverse", mediaPlayerActiveFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerRepeatShuffleIcon: icon {
|
||||||
|
{ "player/player_repeat_shuffle", mediaPlayerActiveFg, point(9px, 11px)}
|
||||||
|
};
|
||||||
|
mediaPlayerRepeatDisabledRippleBg: windowBgOver;
|
||||||
|
|
||||||
mediaPlayerSpeedButton: IconButton {
|
mediaPlayerSpeedButton: IconButton {
|
||||||
width: 31px;
|
width: 31px;
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
#include "media/player/media_player_repeat_controls.h"
|
||||||
|
|
||||||
|
#include "media/player/media_player_dropdown.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "styles/style_media_player.h"
|
||||||
|
|
||||||
|
namespace Media::Player {
|
||||||
|
|
||||||
|
void PrepareRepeatDropdown(
|
||||||
|
not_null<Dropdown*> dropdown,
|
||||||
|
not_null<Window::SessionController*> controller) {
|
||||||
|
const auto makeButton = [&] {
|
||||||
|
const auto result = Ui::CreateChild<Ui::IconButton>(
|
||||||
|
dropdown.get(),
|
||||||
|
st::mediaPlayerRepeatButton);
|
||||||
|
result->show();
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto repeatOne = makeButton();
|
||||||
|
const auto repeat = makeButton();
|
||||||
|
const auto shuffle = makeButton();
|
||||||
|
const auto reverse = makeButton();
|
||||||
|
|
||||||
|
repeatOne->setIconOverride(&st::mediaPlayerRepeatOneIcon);
|
||||||
|
shuffle->setIconOverride(&st::mediaPlayerShuffleIcon);
|
||||||
|
reverse->setIconOverride(&st::mediaPlayerReverseIcon);
|
||||||
|
|
||||||
|
dropdown->sizeValue(
|
||||||
|
) | rpl::start_with_next([=](QSize size) {
|
||||||
|
const auto rect = QRect(QPoint(), size);
|
||||||
|
const auto inner = rect.marginsRemoved(dropdown->getMargin());
|
||||||
|
const auto skip = (inner.height() - repeatOne->height() * 4) / 3;
|
||||||
|
auto top = 0;
|
||||||
|
const auto move = [&](auto &widget) {
|
||||||
|
widget->move((size.width() - widget->width()) / 2, top);
|
||||||
|
top += widget->height() + skip;
|
||||||
|
};
|
||||||
|
move(repeatOne);
|
||||||
|
move(repeat);
|
||||||
|
move(shuffle);
|
||||||
|
move(reverse);
|
||||||
|
}, dropdown->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Media::Player
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
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 Window {
|
||||||
|
class SessionController;
|
||||||
|
} // namespace Window
|
||||||
|
|
||||||
|
namespace Media::Player {
|
||||||
|
|
||||||
|
class Dropdown;
|
||||||
|
|
||||||
|
void PrepareRepeatDropdown(
|
||||||
|
not_null<Dropdown*> dropdown,
|
||||||
|
not_null<Window::SessionController*> controller);
|
||||||
|
|
||||||
|
} // namespace Media::Player
|
|
@ -398,6 +398,17 @@ void Widget::volumeWidgetCreated(Dropdown *widget) {
|
||||||
_volumeToggle->installEventFilter(widget);
|
_volumeToggle->installEventFilter(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPoint Widget::getPositionForRepeatWidget() const {
|
||||||
|
auto x = _repeatToggle->x();
|
||||||
|
x += (_repeatToggle->width() - st::mediaPlayerVolumeSize.width()) / 2;
|
||||||
|
if (rtl()) x = width() - x - st::mediaPlayerVolumeSize.width();
|
||||||
|
return QPoint(x, height());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::repeatWidgetCreated(Dropdown *widget) {
|
||||||
|
_repeatToggle->installEventFilter(widget);
|
||||||
|
}
|
||||||
|
|
||||||
Widget::~Widget() = default;
|
Widget::~Widget() = default;
|
||||||
|
|
||||||
void Widget::handleSeekProgress(float64 progress) {
|
void Widget::handleSeekProgress(float64 progress) {
|
||||||
|
|
|
@ -53,6 +53,9 @@ public:
|
||||||
QPoint getPositionForVolumeWidget() const;
|
QPoint getPositionForVolumeWidget() const;
|
||||||
void volumeWidgetCreated(Dropdown *widget);
|
void volumeWidgetCreated(Dropdown *widget);
|
||||||
|
|
||||||
|
QPoint getPositionForRepeatWidget() const;
|
||||||
|
void repeatWidgetCreated(Dropdown *widget);
|
||||||
|
|
||||||
~Widget();
|
~Widget();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|