2016-07-11 18:05:46 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop version of Telegram messaging app, see https://telegram.org
|
|
|
|
|
|
|
|
Telegram Desktop is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
It is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
In addition, as a special exception, the copyright holders give permission
|
|
|
|
to link the code of portions of this program with the OpenSSL library.
|
|
|
|
|
|
|
|
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
|
|
|
Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org
|
|
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "media/view/media_clip_controller.h"
|
|
|
|
|
|
|
|
#include "media/view/media_clip_playback.h"
|
|
|
|
#include "media/view/media_clip_volume_controller.h"
|
|
|
|
#include "styles/style_mediaview.h"
|
|
|
|
#include "ui/widgets/label_simple.h"
|
|
|
|
#include "ui/effects/fade_animation.h"
|
|
|
|
#include "ui/buttons/icon_button.h"
|
|
|
|
#include "media/media_audio.h"
|
|
|
|
|
|
|
|
namespace Media {
|
|
|
|
namespace Clip {
|
|
|
|
|
|
|
|
Controller::Controller(QWidget *parent) : TWidget(parent)
|
|
|
|
, _playPauseResume(this, st::mediaviewPlayButton)
|
|
|
|
, _playback(this)
|
|
|
|
, _volumeController(this)
|
|
|
|
, _fullScreenToggle(this, st::mediaviewFullScreenButton)
|
|
|
|
, _playedAlready(this, st::mediaviewPlayProgressLabel)
|
|
|
|
, _toPlayLeft(this, st::mediaviewPlayProgressLabel)
|
|
|
|
, _fadeAnimation(std_::make_unique<Ui::FadeAnimation>(this)) {
|
|
|
|
_fadeAnimation->show();
|
2016-07-12 11:38:16 +00:00
|
|
|
_fadeAnimation->setFinishedCallback(func(this, &Controller::fadeFinished));
|
|
|
|
_fadeAnimation->setUpdatedCallback(func(this, &Controller::fadeUpdated));
|
2016-07-12 14:11:59 +00:00
|
|
|
|
|
|
|
_volumeController->setVolume(Global::VideoVolume());
|
|
|
|
|
2016-07-11 18:05:46 +00:00
|
|
|
connect(_playPauseResume, SIGNAL(clicked()), this, SIGNAL(playPressed()));
|
|
|
|
connect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed()));
|
2016-07-13 17:34:57 +00:00
|
|
|
connect(_playback, SIGNAL(seekProgress(float64)), this, SLOT(onSeekProgress(float64)));
|
|
|
|
connect(_playback, SIGNAL(seekFinished(float64)), this, SLOT(onSeekFinished(float64)));
|
2016-07-11 18:05:46 +00:00
|
|
|
connect(_volumeController, SIGNAL(volumeChanged(float64)), this, SIGNAL(volumeChanged(float64)));
|
|
|
|
}
|
|
|
|
|
2016-07-13 17:34:57 +00:00
|
|
|
void Controller::onSeekProgress(float64 progress) {
|
|
|
|
if (!_lastDurationMs) return;
|
|
|
|
|
|
|
|
auto positionMs = snap(static_cast<int64>(progress * _lastDurationMs), 0LL, _lastDurationMs);
|
|
|
|
if (_seekPositionMs != positionMs) {
|
|
|
|
_seekPositionMs = positionMs;
|
|
|
|
refreshTimeTexts();
|
2016-07-29 16:33:49 +00:00
|
|
|
emit seekProgress(positionMs); // This may destroy Controller.
|
2016-07-13 17:34:57 +00:00
|
|
|
}
|
2016-07-11 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 17:34:57 +00:00
|
|
|
void Controller::onSeekFinished(float64 progress) {
|
|
|
|
if (!_lastDurationMs) return;
|
|
|
|
|
|
|
|
auto positionMs = snap(static_cast<int64>(progress * _lastDurationMs), 0LL, _lastDurationMs);
|
|
|
|
_seekPositionMs = -1;
|
|
|
|
emit seekFinished(positionMs);
|
|
|
|
refreshTimeTexts();
|
2016-07-11 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::showAnimated() {
|
2016-07-12 11:38:16 +00:00
|
|
|
startFading([this]() {
|
|
|
|
_fadeAnimation->fadeIn(st::mvShowDuration);
|
|
|
|
});
|
2016-07-11 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::hideAnimated() {
|
2016-07-12 11:38:16 +00:00
|
|
|
startFading([this]() {
|
2016-07-12 18:04:34 +00:00
|
|
|
_fadeAnimation->fadeOut(st::mvHideDuration);
|
2016-07-12 11:38:16 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Callback>
|
|
|
|
void Controller::startFading(Callback start) {
|
|
|
|
start();
|
|
|
|
_playback->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::fadeFinished() {
|
|
|
|
fadeUpdated(1.);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::fadeUpdated(float64 opacity) {
|
|
|
|
_playback->setFadeOpacity(opacity);
|
2016-07-11 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
2016-07-13 17:34:57 +00:00
|
|
|
void Controller::updatePlayback(const AudioPlaybackState &playbackState, bool reset) {
|
2016-07-12 11:38:16 +00:00
|
|
|
updatePlayPauseResumeState(playbackState);
|
2016-07-13 17:34:57 +00:00
|
|
|
_playback->updateState(playbackState, reset);
|
2016-07-12 11:38:16 +00:00
|
|
|
updateTimeTexts(playbackState);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::updatePlayPauseResumeState(const AudioPlaybackState &playbackState) {
|
2016-07-13 17:34:57 +00:00
|
|
|
bool showPause = (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || _seekPositionMs >= 0);
|
2016-07-11 18:05:46 +00:00
|
|
|
if (showPause != _showPause) {
|
|
|
|
disconnect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed()));
|
|
|
|
_showPause = showPause;
|
|
|
|
connect(_playPauseResume, SIGNAL(clicked()), this, _showPause ? SIGNAL(pausePressed()) : SIGNAL(playPressed()));
|
|
|
|
|
|
|
|
_playPauseResume->setIcon(_showPause ? &st::mediaviewPauseIcon : nullptr);
|
|
|
|
}
|
2016-07-12 11:38:16 +00:00
|
|
|
}
|
2016-07-11 18:05:46 +00:00
|
|
|
|
2016-07-12 11:38:16 +00:00
|
|
|
void Controller::updateTimeTexts(const AudioPlaybackState &playbackState) {
|
|
|
|
qint64 position = 0, duration = playbackState.duration;
|
|
|
|
|
|
|
|
if (!(playbackState.state & AudioPlayerStoppedMask) && playbackState.state != AudioPlayerFinishing) {
|
|
|
|
position = playbackState.position;
|
|
|
|
} else if (playbackState.state == AudioPlayerStoppedAtEnd) {
|
|
|
|
position = playbackState.duration;
|
|
|
|
} else {
|
|
|
|
position = 0;
|
|
|
|
}
|
|
|
|
auto playFrequency = (playbackState.frequency ? playbackState.frequency : AudioVoiceMsgFrequency);
|
|
|
|
auto playAlready = position / playFrequency;
|
|
|
|
auto playLeft = (playbackState.duration / playFrequency) - playAlready;
|
|
|
|
|
2016-07-13 17:34:57 +00:00
|
|
|
_lastDurationMs = (playbackState.duration * 1000LL) / playFrequency;
|
|
|
|
|
|
|
|
_timeAlready = formatDurationText(playAlready);
|
2016-07-12 11:38:16 +00:00
|
|
|
auto minus = QChar(8722);
|
2016-07-13 17:34:57 +00:00
|
|
|
_timeLeft = minus + formatDurationText(playLeft);
|
2016-07-12 11:38:16 +00:00
|
|
|
|
2016-07-13 17:34:57 +00:00
|
|
|
if (_seekPositionMs < 0) {
|
|
|
|
refreshTimeTexts();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::refreshTimeTexts() {
|
2016-07-12 11:38:16 +00:00
|
|
|
auto alreadyChanged = false, leftChanged = false;
|
2016-07-13 17:34:57 +00:00
|
|
|
auto timeAlready = _timeAlready;
|
|
|
|
auto timeLeft = _timeLeft;
|
|
|
|
if (_seekPositionMs >= 0) {
|
|
|
|
auto playAlready = _seekPositionMs / 1000LL;
|
|
|
|
auto playLeft = (_lastDurationMs / 1000LL) - playAlready;
|
|
|
|
|
|
|
|
timeAlready = formatDurationText(playAlready);
|
|
|
|
auto minus = QChar(8722);
|
|
|
|
timeLeft = minus + formatDurationText(playLeft);
|
|
|
|
}
|
|
|
|
|
2016-07-12 11:38:16 +00:00
|
|
|
_playedAlready->setText(timeAlready, &alreadyChanged);
|
|
|
|
_toPlayLeft->setText(timeLeft, &leftChanged);
|
|
|
|
if (alreadyChanged || leftChanged) {
|
2016-07-16 06:54:02 +00:00
|
|
|
resizeEvent(nullptr);
|
2016-07-12 11:38:16 +00:00
|
|
|
_fadeAnimation->refreshCache();
|
|
|
|
}
|
2016-07-11 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::setInFullScreen(bool inFullScreen) {
|
|
|
|
_fullScreenToggle->setIcon(inFullScreen ? &st::mediaviewFullScreenOutIcon : nullptr);
|
|
|
|
disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(toFullScreenPressed()));
|
|
|
|
disconnect(_fullScreenToggle, SIGNAL(clicked()), this, SIGNAL(fromFullScreenPressed()));
|
|
|
|
|
|
|
|
auto handler = inFullScreen ? SIGNAL(fromFullScreenPressed()) : SIGNAL(toFullScreenPressed());
|
|
|
|
connect(_fullScreenToggle, SIGNAL(clicked()), this, handler);
|
|
|
|
}
|
|
|
|
|
2016-07-12 11:38:16 +00:00
|
|
|
void Controller::grabStart() {
|
|
|
|
showChildren();
|
|
|
|
_playback->hide();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::grabFinish() {
|
|
|
|
hideChildren();
|
|
|
|
_playback->show();
|
|
|
|
}
|
|
|
|
|
2016-07-11 18:05:46 +00:00
|
|
|
void Controller::resizeEvent(QResizeEvent *e) {
|
|
|
|
int playTop = (height() - _playPauseResume->height()) / 2;
|
2016-08-03 11:02:53 +00:00
|
|
|
_playPauseResume->moveToLeft(st::mediaviewPlayPauseLeft, playTop);
|
2016-07-11 18:05:46 +00:00
|
|
|
|
|
|
|
int fullScreenTop = (height() - _fullScreenToggle->height()) / 2;
|
2016-08-03 11:02:53 +00:00
|
|
|
_fullScreenToggle->moveToRight(st::mediaviewPlayPauseLeft, fullScreenTop);
|
2016-07-11 18:05:46 +00:00
|
|
|
|
2016-08-03 11:02:53 +00:00
|
|
|
_volumeController->moveToRight(st::mediaviewPlayPauseLeft + _fullScreenToggle->width() + st::mediaviewVolumeLeft, (height() - _volumeController->height()) / 2);
|
|
|
|
_playback->resize(width() - st::mediaviewPlayPauseLeft - _playPauseResume->width() - playTop - fullScreenTop - _volumeController->width() - st::mediaviewVolumeLeft - _fullScreenToggle->width() - st::mediaviewPlayPauseLeft, st::mediaviewSeekSize.height());
|
|
|
|
_playback->moveToLeft(st::mediaviewPlayPauseLeft + _playPauseResume->width() + playTop, st::mediaviewPlaybackTop);
|
2016-07-12 11:38:16 +00:00
|
|
|
|
2016-08-03 11:02:53 +00:00
|
|
|
_playedAlready->moveToLeft(st::mediaviewPlayPauseLeft + _playPauseResume->width() + playTop, st::mediaviewPlayProgressTop);
|
|
|
|
_toPlayLeft->moveToRight(width() - (st::mediaviewPlayPauseLeft + _playPauseResume->width() + playTop) - _playback->width(), st::mediaviewPlayProgressTop);
|
2016-07-11 18:05:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Controller::paintEvent(QPaintEvent *e) {
|
|
|
|
Painter p(this);
|
|
|
|
|
|
|
|
if (_fadeAnimation->paint(p)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
App::roundRect(p, rect(), st::medviewSaveMsg, MediaviewSaveCorners);
|
|
|
|
}
|
|
|
|
|
2016-07-12 14:11:59 +00:00
|
|
|
void Controller::mousePressEvent(QMouseEvent *e) {
|
|
|
|
e->accept(); // Don't pass event to the MediaView.
|
|
|
|
}
|
|
|
|
|
2016-07-19 12:31:48 +00:00
|
|
|
Controller::~Controller() {
|
|
|
|
}
|
|
|
|
|
2016-07-11 18:05:46 +00:00
|
|
|
} // namespace Clip
|
|
|
|
} // namespace Media
|