Display correct video / music state.

This commit is contained in:
John Preston 2019-03-01 15:16:55 +04:00
parent fde8dd9607
commit 648cd44ddd
17 changed files with 301 additions and 129 deletions

View File

@ -301,7 +301,7 @@ void DocumentOpenClickHandler::Open(
location.accessDisable();
return;
} else if (data->canBePlayed()) {
if (data->isAudioFile()) {
if (data->isAudioFile() || data->isVoiceMessage()) {
Media::Player::instance()->playPause({ data, msgId });
} else {
Core::App().showDocument(data, context);
@ -615,7 +615,9 @@ void DocumentData::replaceGoodThumbnail(
_goodThumbnail->replaceSource(std::move(source));
}
void DocumentData::setGoodThumbnail(QImage &&image, QByteArray &&bytes) {
void DocumentData::setGoodThumbnailOnUpload(
QImage &&image,
QByteArray &&bytes) {
Expects(uploadingData != nullptr);
if (image.isNull()) {
@ -1215,7 +1217,10 @@ bool DocumentData::canBeStreamed() const {
}
bool DocumentData::canBePlayed() const {
return (isAnimation() || isVideoFile() || isAudioFile())
return (isAnimation()
|| isVideoFile()
|| isAudioFile()
|| isVoiceMessage())
&& (loaded() || canBeStreamed());
}

View File

@ -184,7 +184,7 @@ public:
[[nodiscard]] Image *goodThumbnail() const;
[[nodiscard]] Storage::Cache::Key goodThumbnailCacheKey() const;
void setGoodThumbnail(QImage &&image, QByteArray &&bytes);
void setGoodThumbnailOnUpload(QImage &&image, QByteArray &&bytes);
void refreshGoodThumbnail();
void replaceGoodThumbnail(std::unique_ptr<Images::Source> &&source);

View File

@ -59,7 +59,8 @@ MTPDmessage::Flags NewForwardedFlags(
result &= ~MTPDmessage::Flag::f_media;
}
}
if (!peer->isChannel() && media->forwardedBecomesUnread()) {
if ((!peer->isChannel() || peer->isMegagroup())
&& media->forwardedBecomesUnread()) {
result |= MTPDmessage::Flag::f_media_unread;
}
}

View File

@ -4300,7 +4300,7 @@ void HistoryWidget::sendFileConfirmed(
MTP_long(groupId)),
NewMessageUnread);
} else if (file->type == SendMediaType::Audio) {
if (!peer->isChannel()) {
if (!peer->isChannel() || peer->isMegagroup()) {
flags |= MTPDmessage::Flag::f_media_unread;
}
auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;

View File

@ -315,10 +315,10 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection,
}
auto icon = [&] {
if (showPause) {
return &(outbg ? (selected ? st::historyFileOutPauseSelected : st::historyFileOutPause) : (selected ? st::historyFileInPauseSelected : st::historyFileInPause));
} else if (radial || _data->loading()) {
if (_data->loading() || _data->uploading()) {
return &(outbg ? (selected ? st::historyFileOutCancelSelected : st::historyFileOutCancel) : (selected ? st::historyFileInCancelSelected : st::historyFileInCancel));
} else if (showPause) {
return &(outbg ? (selected ? st::historyFileOutPauseSelected : st::historyFileOutPause) : (selected ? st::historyFileInPauseSelected : st::historyFileInPause));
} else if (loaded || _data->canBePlayed()) {
if (_data->canBePlayed()) {
return &(outbg ? (selected ? st::historyFileOutPlaySelected : st::historyFileOutPlay) : (selected ? st::historyFileInPlaySelected : st::historyFileInPlay));
@ -335,7 +335,7 @@ void HistoryDocument::draw(Painter &p, const QRect &r, TextSelection selection,
auto statuswidth = namewidth;
auto voiceStatusOverride = QString();
if (auto voice = Get<HistoryDocumentVoice>()) {
if (const auto voice = Get<HistoryDocumentVoice>()) {
const VoiceWaveform *wf = nullptr;
uchar norm_value = 0;
if (const auto voiceData = _data->voice()) {
@ -463,6 +463,13 @@ TextState HistoryDocument::textState(QPoint point, StateRequest request) const {
nametop = st::msgFileThumbNameTop - topMinus;
linktop = st::msgFileThumbLinkTop - topMinus;
bottom = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() - topMinus;
QRect rthumb(rtlrect(st::msgFileThumbPadding.left(), st::msgFileThumbPadding.top() - topMinus, st::msgFileThumbSize, st::msgFileThumbSize, width()));
if ((_data->loading() || _data->uploading()) && rthumb.contains(point)) {
result.link = _cancell;
return result;
}
if (_data->status != FileUploadFailed) {
if (rtlrect(nameleft, linktop, thumbed->_linkw, st::semiboldFont->height, width()).contains(point)) {
result.link = (_data->loading() || _data->uploading())
@ -471,6 +478,17 @@ TextState HistoryDocument::textState(QPoint point, StateRequest request) const {
return result;
}
}
} else {
nameleft = st::msgFilePadding.left() + st::msgFileSize + st::msgFilePadding.right();
nameright = st::msgFilePadding.left();
nametop = st::msgFileNameTop - topMinus;
bottom = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom() - topMinus;
QRect inner(rtlrect(st::msgFilePadding.left(), st::msgFilePadding.top() - topMinus, st::msgFileSize, st::msgFileSize, width()));
if ((_data->loading() || _data->uploading()) && inner.contains(point)) {
result.link = _cancell;
return result;
}
}
if (const auto voice = Get<HistoryDocumentVoice>()) {
@ -490,7 +508,7 @@ TextState HistoryDocument::textState(QPoint point, StateRequest request) const {
}
auto painth = height();
if (auto captioned = Get<HistoryDocumentCaptioned>()) {
if (const auto captioned = Get<HistoryDocumentCaptioned>()) {
if (point.y() >= bottom) {
result = TextState(_parent, captioned->_caption.getState(
point - QPoint(st::msgPadding.left(), bottom),
@ -504,10 +522,11 @@ TextState HistoryDocument::textState(QPoint point, StateRequest request) const {
painth -= st::msgPadding.bottom();
}
}
if (QRect(0, 0, width(), painth).contains(point) && !_data->loading() && !_data->uploading() && !_data->isNull()) {
if (_data->loading() || _data->uploading()) {
result.link = _cancell;
} else if (loaded || _data->canBePlayed()) {
if (QRect(0, 0, width(), painth).contains(point)
&& !_data->loading()
&& !_data->uploading()
&& !_data->isNull()) {
if (loaded || _data->canBePlayed()) {
result.link = _openl;
} else {
result.link = _savel;

View File

@ -226,15 +226,13 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, crl
p.setOpacity(1);
}
const auto canPlay = _data->canBePlayed();
auto icon = [&]() -> const style::icon * {
if (canPlay && !radial) {
return &(selected ? st::historyFileThumbPlaySelected : st::historyFileThumbPlay);
} else if (radial || _data->loading()) {
if (_parent->data()->id > 0 || _data->uploading()) {
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
}
if (_data->loading() || _data->uploading()) {
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
} else if (!IsServerMsgId(_parent->data()->id)) {
return nullptr;
} else if (_data->canBePlayed()) {
return &(selected ? st::historyFileThumbPlaySelected : st::historyFileThumbPlay);
}
return &(selected ? st::historyFileThumbDownloadSelected : st::historyFileThumbDownload);
}();
@ -276,7 +274,6 @@ TextState HistoryVideo::textState(QPoint point, StateRequest request) const {
}
auto result = TextState(_parent);
const auto canPlay = _data->canBePlayed();
auto paintx = 0, painty = 0, paintw = width(), painth = height();
bool bubble = _parent->hasBubble();
@ -298,10 +295,13 @@ TextState HistoryVideo::textState(QPoint point, StateRequest request) const {
painth -= st::mediaCaptionSkip;
}
if (QRect(paintx, painty, paintw, painth).contains(point)) {
if (_data->uploading()) {
if (_data->loading() || _data->uploading()) {
result.link = _cancell;
} else if (!IsServerMsgId(_parent->data()->id)) {
} else if (_data->canBePlayed()) {
result.link = _openl;
} else {
result.link = canPlay ? _openl : (_data->loading() ? _cancell : _savel);
result.link = _savel;
}
}
if (_caption.isEmpty() && _parent->media() == this) {
@ -394,13 +394,12 @@ void HistoryVideo::drawGrouped(
auto icon = [&]() -> const style::icon * {
if (_data->waitingForAlbum()) {
return &(selected ? st::historyFileThumbWaitingSelected : st::historyFileThumbWaiting);
} else if (canPlay && !radial) {
return &(selected ? st::historyFileThumbPlaySelected : st::historyFileThumbPlay);
} else if (radial || _data->loading()) {
if (_parent->data()->id > 0 || _data->uploading()) {
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
}
} else if (_data->loading() || _data->uploading()) {
return &(selected ? st::historyFileThumbCancelSelected : st::historyFileThumbCancel);
} else if (!IsServerMsgId(_realParent->id)) {
return nullptr;
} else if (_data->canBePlayed()) {
return &(selected ? st::historyFileThumbPlaySelected : st::historyFileThumbPlay);
}
return &(selected ? st::historyFileThumbDownloadSelected : st::historyFileThumbDownload);
}();
@ -436,12 +435,12 @@ TextState HistoryVideo::getStateGrouped(
if (!geometry.contains(point)) {
return {};
}
return TextState(_parent, _data->uploading()
return TextState(_parent, (_data->loading() || _data->uploading())
? _cancell
: !IsServerMsgId(_realParent->id)
? nullptr
: _data->canBePlayed()
? _openl
: _data->loading()
? _cancell
: _savel);
}

View File

@ -188,14 +188,14 @@ void Gif::paint(Painter &p, const QRect &clip, const PaintContext *context) cons
p.setOpacity(radialOpacity * p.opacity());
p.setOpacity(radialOpacity);
auto icon = ([loaded, radial, loading] {
if (loaded && !radial) {
return &st::historyFileInPlay;
} else if (radial || loading) {
auto icon = [&] {
if (radial || loading) {
return &st::historyFileInCancel;
} else if (loaded) {
return &st::historyFileInPlay;
}
return &st::historyFileInDownload;
})();
}();
QRect inner((_width - st::msgFileSize) / 2, (height - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
icon->paintInCenter(p, inner);
if (radial) {
@ -778,11 +778,11 @@ void File::paint(Painter &p, const QRect &clip, const PaintContext *context) con
_animation->radial.draw(p, radialCircle, st::msgFileRadialLine, st::historyFileInRadialFg);
}
auto icon = ([&] {
if (showPause) {
return &st::historyFileInPause;
} else if (radial || _document->loading()) {
auto icon = [&] {
if (radial || _document->loading()) {
return &st::historyFileInCancel;
} else if (showPause) {
return &st::historyFileInPause;
} else if (true || _document->loaded()) {
if (_document->isImage()) {
return &st::historyFileInImage;
@ -793,7 +793,7 @@ void File::paint(Painter &p, const QRect &clip, const PaintContext *context) con
return &st::historyFileInDocument;
}
return &st::historyFileInDownload;
})();
}();
icon->paintInCenter(p, inner);
int titleTop = st::inlineRowMargin + st::inlineRowFileNameTop;

View File

@ -798,27 +798,6 @@ void Mixer::play(
auto current = trackForType(type);
if (!current) return;
if (type == AudioMsgId::Type::Video) {
auto pauseType = [this](AudioMsgId::Type type) {
auto current = trackForType(type);
switch (current->state.state) {
case State::Starting:
case State::Resuming:
case State::Playing: {
current->state.state = State::Pausing;
resetFadeStartPosition(type);
} break;
case State::Stopping: {
current->state.state = State::Pausing;
} break;
}
};
pauseType(AudioMsgId::Type::Song);
pauseType(AudioMsgId::Type::Voice);
}
if (current->state.id != audio) {
if (fadedStop(type, &fadedStart)) {
stopped = current->state.id;

View File

@ -78,6 +78,7 @@ using PreloadedAudio = PreloadedUpdate<AudioTrack>;
using UpdateAudio = PlaybackUpdate<AudioTrack>;
struct WaitingForData {
bool waiting = false;
};
struct MutedByOther {

View File

@ -450,6 +450,7 @@ void Player::checkResumeFromWaitingForData() {
if (_pausedByWaitingForData && bothReceivedEnough(kBufferFor)) {
_pausedByWaitingForData = false;
updatePausedState();
_updates.fire({ WaitingForData{ false } });
}
}
@ -467,7 +468,7 @@ void Player::start() {
}) | rpl::start_with_next([=] {
_pausedByWaitingForData = true;
updatePausedState();
_updates.fire({ WaitingForData() });
_updates.fire({ WaitingForData{ true } });
}, _sessionLifetime);
if (guard && _audio) {

View File

@ -19,11 +19,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image.h"
#include "ui/text_options.h"
#include "media/audio/media_audio.h"
#include "media/clip/media_clip_reader.h"
#include "media/view/media_view_playback_controls.h"
#include "media/view/media_view_group_thumbs.h"
#include "media/streaming/media_streaming_player.h"
#include "media/streaming/media_streaming_loader.h"
#include "media/player/media_player_instance.h"
#include "history/history.h"
#include "history/history_message.h"
#include "data/data_media_types.h"
@ -45,6 +45,10 @@ namespace Media {
namespace View {
namespace {
constexpr auto kGoodThumbnailQuality = 87;
constexpr auto kWaitingFastDuration = crl::time(200);
constexpr auto kWaitingShowDuration = crl::time(500);
constexpr auto kWaitingShowDelay = crl::time(500);
constexpr auto kPreloadCount = 4;
// Preload X message ids before and after current.
@ -146,20 +150,30 @@ struct OverlayWidget::Streamed {
not_null<Data::Session*> owner,
std::unique_ptr<Streaming::Loader> loader,
QWidget *controlsParent,
not_null<PlaybackControls::Delegate*> controlsDelegate);
not_null<PlaybackControls::Delegate*> controlsDelegate,
AnimationCallbacks loadingCallbacks);
Streaming::Player player;
Streaming::Information info;
PlaybackControls controls;
bool waiting = false;
Ui::InfiniteRadialAnimation radial;
Animation fading;
base::Timer timer;
bool resumeOnCallEnd = false;
};
OverlayWidget::Streamed::Streamed(
not_null<Data::Session*> owner,
std::unique_ptr<Streaming::Loader> loader,
QWidget *controlsParent,
not_null<PlaybackControls::Delegate*> controlsDelegate)
not_null<PlaybackControls::Delegate*> controlsDelegate,
AnimationCallbacks loadingCallbacks)
: player(owner, std::move(loader))
, controls(controlsParent, controlsDelegate) {
, controls(controlsParent, controlsDelegate)
, radial(std::move(loadingCallbacks), st::mediaviewStreamingRadial) {
}
OverlayWidget::OverlayWidget()
@ -195,11 +209,13 @@ OverlayWidget::OverlayWidget()
}
});
subscribe(Auth().calls().currentCallChanged(), [this](Calls::Call *call) {
if (call
&& _streamed
&& !_streamed->player.paused()
&& !_streamed->player.finished()) {
playbackPauseResume();
if (!_streamed) {
return;
}
if (call) {
playbackPauseOnCall();
} else {
playbackResumeOnCall();
}
});
subscribe(Auth().documentUpdated, [this](DocumentData *document) {
@ -644,6 +660,12 @@ void OverlayWidget::step_state(crl::time ms, bool timer) {
}
}
void OverlayWidget::step_waiting(crl::time ms, bool timer) {
if (timer && !anim::Disabled()) {
update(radialRect());
}
}
void OverlayWidget::updateCursor() {
setCursor(_controlsState == ControlsHidden
? Qt::BlankCursor
@ -665,7 +687,7 @@ float64 OverlayWidget::radialProgress() const {
bool OverlayWidget::radialLoading() const {
if (_doc) {
return _doc->loading();
return _doc->loading() && !_streamed;
} else if (_photo) {
return _photo->large()->loading();
}
@ -695,7 +717,7 @@ crl::time OverlayWidget::radialTimeShift() const {
}
void OverlayWidget::step_radial(crl::time ms, bool timer) {
if (!_doc && !_photo) {
if ((!_doc && !_photo) || _streamed) {
_radial.stop();
return;
}
@ -911,7 +933,7 @@ void OverlayWidget::onScreenResized(int screen) {
}
if (!ignore) {
moveToScreen();
auto item = (_msgid ? App::histItemById(_msgid) : nullptr);
const auto item = App::histItemById(_msgid);
if (_photo) {
displayPhoto(_photo, item);
} else if (_doc) {
@ -921,7 +943,7 @@ void OverlayWidget::onScreenResized(int screen) {
}
void OverlayWidget::onToMessage() {
if (auto item = _msgid ? App::histItemById(_msgid) : 0) {
if (const auto item = App::histItemById(_msgid)) {
close();
Ui::showPeerHistoryAtItem(item);
}
@ -1873,17 +1895,36 @@ void OverlayWidget::initStreaming() {
}
void OverlayWidget::initStreamingThumbnail() {
if (!_doc->hasThumbnail()) {
Expects(_doc != nullptr);
const auto good = _doc->goodThumbnail();
const auto useGood = (good && good->loaded());
const auto thumb = _doc->thumbnail();
const auto useThumb = (thumb && thumb->loaded());
const auto blurred = _doc->thumbnailInline();
if (!useGood && !thumb && !blurred) {
return;
} else if (_doc->dimensions.isEmpty()) {
return;
}
if (_doc->dimensions.width() && _doc->dimensions.height()) {
auto w = _doc->dimensions.width();
auto h = _doc->dimensions.height();
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), w, h, VideoThumbOptions(_doc), w / cIntRetinaFactor(), h / cIntRetinaFactor());
_current.setDevicePixelRatio(cRetinaFactor());
} else {
_current = _doc->thumbnail()->pixNoCache(fileOrigin(), _doc->thumbnail()->width(), _doc->thumbnail()->height(), VideoThumbOptions(_doc), st::mediaviewFileIconSize, st::mediaviewFileIconSize);
}
const auto w = _doc->dimensions.width();
const auto h = _doc->dimensions.height();
const auto options = VideoThumbOptions(_doc);
const auto goodOptions = (options & ~Images::Option::Blurred);
_current = (useGood
? good
: useThumb
? thumb
: blurred
? blurred
: Image::BlankMedia().get())->pixNoCache(
fileOrigin(),
w,
h,
useGood ? goodOptions : options,
w / cIntRetinaFactor(),
h / cIntRetinaFactor());
_current.setDevicePixelRatio(cRetinaFactor());
}
void OverlayWidget::createStreamingObjects() {
@ -1891,7 +1932,8 @@ void OverlayWidget::createStreamingObjects() {
&_doc->owner(),
_doc->createStreamingLoader(fileOrigin()),
this,
static_cast<PlaybackControls::Delegate *>(this));
static_cast<PlaybackControls::Delegate*>(this),
animation(this, &OverlayWidget::step_waiting));
if (videoIsGifv()) {
_streamed->controls.hide();
@ -1901,27 +1943,61 @@ void OverlayWidget::createStreamingObjects() {
}
}
void OverlayWidget::validateStreamedGoodThumbnail() {
Expects(_streamed != nullptr);
Expects(_doc != nullptr);
const auto good = _doc->goodThumbnail();
const auto &image = _streamed->info.video.cover;
if (image.isNull() || (good && good->loaded()) || _doc->uploading()) {
return;
}
auto bytes = QByteArray();
{
auto buffer = QBuffer(&bytes);
image.save(&buffer, "JPG", kGoodThumbnailQuality);
}
const auto length = bytes.size();
if (!length || length > Storage::kMaxFileInMemory) {
LOG(("App Error: Bad thumbnail data for saving to cache."));
} else if (_doc->uploading()) {
_doc->setGoodThumbnailOnUpload(
base::duplicate(image),
std::move(bytes));
} else {
_doc->owner().cache().putIfEmpty(
_doc->goodThumbnailCacheKey(),
Storage::Cache::Database::TaggedValue(
std::move(bytes),
Data::kImageCacheTag));
_doc->refreshGoodThumbnail();
}
}
void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) {
using namespace Streaming;
update.data.match([&](Information &update) {
_streamed->info = std::move(update);
validateStreamedGoodThumbnail();
this->update(contentRect());
}, [&](PreloadedVideo &update) {
playbackWaitingChange(false);
}, [&](const PreloadedVideo &update) {
_streamed->info.video.state.receivedTill = update.till;
//updatePlaybackState();
}, [&](UpdateVideo &update) {
}, [&](const UpdateVideo &update) {
_streamed->info.video.state.position = update.position;
this->update(contentRect());
Core::App().updateNonIdle();
updatePlaybackState();
}, [&](PreloadedAudio &update) {
}, [&](const PreloadedAudio &update) {
_streamed->info.audio.state.receivedTill = update.till;
//updatePlaybackState();
}, [&](UpdateAudio & update) {
}, [&](const UpdateAudio &update) {
_streamed->info.audio.state.position = update.position;
updatePlaybackState();
}, [&](WaitingForData) {
}, [&](const WaitingForData &update) {
playbackWaitingChange(update.waiting);
}, [&](MutedByOther) {
}, [&](Finished) {
const auto finishTrack = [](Media::Streaming::TrackState &state) {
@ -1934,6 +2010,43 @@ void OverlayWidget::handleStreamingUpdate(Streaming::Update &&update) {
}
void OverlayWidget::handleStreamingError(Streaming::Error &&error) {
playbackWaitingChange(false);
}
void OverlayWidget::playbackWaitingChange(bool waiting) {
Expects(_streamed != nullptr);
if (_streamed->waiting == waiting) {
return;
}
_streamed->waiting = waiting;
const auto fade = [=](crl::time duration) {
if (!_streamed->radial.animating()) {
_streamed->radial.start(
st::defaultInfiniteRadialAnimation.sineDuration);
}
_streamed->fading.start(
[=] { update(radialRect()); },
_streamed->waiting ? 0. : 1.,
_streamed->waiting ? 1. : 0.,
duration);
};
if (waiting) {
if (_streamed->radial.animating()) {
_streamed->timer.cancel();
fade(kWaitingFastDuration);
} else {
_streamed->timer.callOnce(kWaitingShowDelay);
_streamed->timer.setCallback([=] {
fade(kWaitingShowDuration);
});
}
} else {
_streamed->timer.cancel();
if (_streamed->radial.animating()) {
fade(kWaitingFastDuration);
}
}
}
void OverlayWidget::initThemePreview() {
@ -2026,13 +2139,16 @@ void OverlayWidget::playbackControlsFromFullScreen() {
void OverlayWidget::playbackPauseResume() {
Expects(_streamed != nullptr);
_streamed->resumeOnCallEnd = false;
if (const auto item = App::histItemById(_msgid)) {
if (_streamed->player.failed()) {
displayDocument(_doc, item);
} else if (_streamed->player.finished()) {
restartAtSeekPosition(0);
} else if (_streamed->player.paused()) {
_streamed->player.resume();
} else {
togglePauseResume();
_streamed->player.pause();
}
} else {
clearStreaming();
@ -2041,32 +2157,28 @@ void OverlayWidget::playbackPauseResume() {
}
}
void OverlayWidget::togglePauseResume() {
Expects(_streamed != nullptr);
if (_streamed->player.paused()) {
_streamed->player.resume();
} else {
_streamed->player.pause();
}
}
void OverlayWidget::restartAtSeekPosition(crl::time position) {
Expects(_streamed != nullptr);
_autoplayVideoDocument = _doc;
if (_current.isNull() && videoShown()) {
if (videoShown()) {
_streamed->info.video.cover = videoFrame();
_current = Images::PixmapFast(videoFrame());
update(contentRect());
}
auto options = Streaming::PlaybackOptions();
options.position = position;
_streamed->player.play(options);
Media::Player::instance()->pause(AudioMsgId::Type::Voice);
Media::Player::instance()->pause(AudioMsgId::Type::Song);
_streamed->info.audio.state.position
= _streamed->info.video.state.position
= position;
updatePlaybackState();
playbackWaitingChange(true);
}
void OverlayWidget::playbackControlsSeekProgress(crl::time position) {
@ -2107,6 +2219,25 @@ void OverlayWidget::playbackToggleFullScreen() {
update();
}
void OverlayWidget::playbackPauseOnCall() {
Expects(_streamed != nullptr);
if (_streamed->player.finished() || _streamed->player.paused()) {
return;
}
_streamed->player.pause();
_streamed->resumeOnCallEnd = true;
}
void OverlayWidget::playbackResumeOnCall() {
Expects(_streamed != nullptr);
if (_streamed->resumeOnCallEnd) {
_streamed->resumeOnCallEnd = false;
_streamed->player.resume();
}
}
void OverlayWidget::updatePlaybackState() {
Expects(_streamed != nullptr);
@ -2464,9 +2595,34 @@ void OverlayWidget::checkGroupThumbsAnimation() {
}
void OverlayWidget::paintDocRadialLoading(Painter &p, bool radial, float64 radialOpacity) {
float64 o = overLevel(OverIcon);
if (radial || (_doc && !_doc->loaded() && !_streamed)) {
QRect inner(QPoint(_docIconRect.x() + ((_docIconRect.width() - st::radialSize.width()) / 2), _docIconRect.y() + ((_docIconRect.height() - st::radialSize.height()) / 2)), st::radialSize);
QRect inner(QPoint(_docIconRect.x() + ((_docIconRect.width() - st::radialSize.width()) / 2), _docIconRect.y() + ((_docIconRect.height() - st::radialSize.height()) / 2)), st::radialSize);
if (_streamed) {
const auto ms = crl::now();
_streamed->radial.step(ms);
if (!_streamed->radial.animating()) {
return;
}
const auto fade = _streamed->fading.current(
ms,
_streamed->waiting ? 1. : 0.);
if (fade == 0.) {
if (!_streamed->waiting) {
_streamed->radial.stop(anim::type::instant);
}
return;
}
p.setOpacity(fade);
p.setPen(Qt::NoPen);
p.setBrush(st::msgDateImgBg);
{
PainterHighQualityEnabler hq(p);
p.drawEllipse(inner);
}
QRect arc(inner.marginsRemoved(QMargins(st::radialLine, st::radialLine, st::radialLine, st::radialLine)));
_streamed->radial.draw(p, arc.topLeft(), arc.size(), width());// , st::radialLine, st::radialFg);
} else if (radial || (_doc && !_doc->loaded())) {
float64 o = overLevel(OverIcon);
p.setPen(Qt::NoPen);
p.setOpacity(_doc->loaded() ? radialOpacity : 1.);
@ -2478,12 +2634,12 @@ void OverlayWidget::paintDocRadialLoading(Painter &p, bool radial, float64 radia
}
p.setOpacity(1.);
auto icon = ([radial, this]() -> const style::icon* {
auto icon = [&]() -> const style::icon* {
if (radial || _doc->loading()) {
return &st::historyFileThumbCancel;
}
return &st::historyFileThumbDownload;
})();
}();
if (icon) {
icon->paintInCenter(p, inner);
}
@ -2549,15 +2705,17 @@ void OverlayWidget::keyPressEvent(QKeyEvent *e) {
const auto ctrl = e->modifiers().testFlag(Qt::ControlModifier);
if (_streamed) {
// Ctrl + F for full screen toggle is in eventFilter().
const auto toggleFull = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) && (e->modifiers().testFlag(Qt::AltModifier) || ctrl);
const auto toggleFull = (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
&& (e->modifiers().testFlag(Qt::AltModifier) || ctrl);
if (toggleFull) {
playbackToggleFullScreen();
return;
} else if (e->key() == Qt::Key_Space) {
playbackPauseResume();
return;
} else if (_fullScreenVideo) {
if (e->key() == Qt::Key_Escape) {
playbackToggleFullScreen();
} else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return || e->key() == Qt::Key_Space) {
playbackPauseResume();
}
return;
}

View File

@ -161,6 +161,9 @@ private:
void playbackControlsFromFullScreen() override;
void playbackPauseResume();
void playbackToggleFullScreen();
void playbackPauseOnCall();
void playbackResumeOnCall();
void playbackWaitingChange(bool waiting);
void updateOver(QPoint mpos);
void moveToScreen();
@ -227,7 +230,6 @@ private:
void updatePlaybackState();
void restartAtSeekPosition(crl::time position);
void togglePauseResume();
void refreshClipControllerGeometry();
void refreshCaptionGeometry();
@ -237,6 +239,7 @@ private:
void createStreamingObjects();
void handleStreamingUpdate(Streaming::Update &&update);
void handleStreamingError(Streaming::Error &&error);
void validateStreamedGoodThumbnail();
void initThemePreview();
void destroyThemePreview();
@ -259,6 +262,7 @@ private:
void step_state(crl::time ms, bool timer);
void step_radial(crl::time ms, bool timer);
void step_waiting(crl::time ms, bool timer);
void zoomIn();
void zoomOut();

View File

@ -187,6 +187,11 @@ mediaviewGroupWidthMax: 160px;
mediaviewGroupSkip: 3px;
mediaviewGroupSkipCurrent: 12px;
mediaviewStreamingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: radialFg;
thickness: radialLine;
}
themePreviewSize: size(903px, 584px);
themePreviewBg: windowBg;
themePreviewOverlayOpacity: 0.8;

View File

@ -693,12 +693,12 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
}
auto icon = [&] {
if (showPause) {
if (_data->loading() || _data->uploading()) {
return &(selected ? _st.songCancelSelected : _st.songCancel);
} else if (showPause) {
return &(selected ? _st.songPauseSelected : _st.songPause);
} else if (_status.size() < 0 || _status.size() == FileStatusSizeLoaded) {
return &(selected ? _st.songPlaySelected : _st.songPlay);
} else if (_data->loading()) {
return &(selected ? _st.songCancelSelected : _st.songCancel);
}
return &(selected ? _st.songDownloadSelected : _st.songDownload);
}();
@ -962,10 +962,10 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
}
auto icon = [&] {
if (showPause) {
return &(selected ? _st.songPauseSelected : _st.songPause);
} else if (_data->loading() || _data->uploading()) {
if (_data->loading() || _data->uploading()) {
return &(selected ? _st.songCancelSelected : _st.songCancel);
} else if (showPause) {
return &(selected ? _st.songPauseSelected : _st.songPause);
} else if (_data->canBePlayed()) {
return &(selected ? _st.songPlaySelected : _st.songPlay);
}
@ -1107,7 +1107,7 @@ TextState Document::getState(
? _cancell
: _data->canBePlayed()
? _openl
: _openl;
: _savel;
return { parent(), link };
}
const auto namerect = rtlrect(
@ -1137,10 +1137,10 @@ TextState Document::getState(
_width);
if (rthumb.contains(point)) {
const auto link = loaded
? _openl
: (_data->loading() || _data->uploading())
const auto link = (_data->loading() || _data->uploading())
? _cancell
: loaded
? _openl
: _savel;
return { parent(), link };
}

View File

@ -201,7 +201,7 @@ void Uploader::upload(
std::move(file->thumb));
document->uploadingData = std::make_unique<Data::UploadState>(
document->size);
document->setGoodThumbnail(
document->setGoodThumbnailOnUpload(
std::move(file->goodThumbnail),
std::move(file->goodThumbnailBytes));
if (!file->content.isEmpty()) {

View File

@ -127,9 +127,9 @@ void InfiniteRadialAnimation::start(crl::time skip) {
}
}
void InfiniteRadialAnimation::stop() {
void InfiniteRadialAnimation::stop(anim::type animated) {
const auto now = crl::now();
if (anim::Disabled()) {
if (anim::Disabled() || animated == anim::type::instant) {
_workFinished = now;
}
if (!_workFinished) {

View File

@ -70,7 +70,7 @@ public:
}
void start(crl::time skip = 0);
void stop();
void stop(anim::type animated = anim::type::normal);
void step(crl::time ms);
void step() {