From d5430736320d084afb17aab22e5e922dcf6faa09 Mon Sep 17 00:00:00 2001
From: John Preston <johnprestonmail@gmail.com>
Date: Thu, 13 Oct 2016 12:12:12 +0300
Subject: [PATCH] Display download progress in the media player playback
 widget.

---
 Telegram/SourceFiles/media/player/media_player.style   |  3 +++
 .../SourceFiles/media/player/media_player_cover.cpp    | 10 ++++++----
 .../SourceFiles/media/player/media_player_widget.cpp   | 10 ++++++----
 .../SourceFiles/media/view/media_clip_playback.cpp     |  7 +++++++
 Telegram/SourceFiles/media/view/media_clip_playback.h  |  1 +
 Telegram/SourceFiles/media/view/mediaview.style        |  2 ++
 Telegram/SourceFiles/mtproto/file_download.cpp         |  6 +++---
 Telegram/SourceFiles/structs.cpp                       |  7 ++-----
 Telegram/SourceFiles/ui/widgets/continuous_slider.cpp  |  2 +-
 Telegram/SourceFiles/ui/widgets/continuous_slider.h    |  2 +-
 Telegram/SourceFiles/ui/widgets/filled_slider.cpp      |  6 +++---
 Telegram/SourceFiles/ui/widgets/media_slider.cpp       | 10 ++++++----
 Telegram/SourceFiles/ui/widgets/widgets.style          |  3 +++
 13 files changed, 44 insertions(+), 25 deletions(-)

diff --git a/Telegram/SourceFiles/media/player/media_player.style b/Telegram/SourceFiles/media/player/media_player.style
index 75412374f..2ac05e0ff 100644
--- a/Telegram/SourceFiles/media/player/media_player.style
+++ b/Telegram/SourceFiles/media/player/media_player.style
@@ -151,6 +151,7 @@ mediaPlayerPlayback: FilledSlider {
 	lineWidth: 2px;
 	activeFg: mediaPlayerActiveFg;
 	inactiveFg: mediaPlayerInactiveFg;
+	disabledFg: #9dd1ef;
 	duration: 150;
 }
 
@@ -217,6 +218,8 @@ mediaPlayerPanelPlayback: MediaSlider {
 	width: 3px;
 	activeFg: mediaPlayerActiveFg;
 	inactiveFg: mediaPlayerInactiveFg;
+	disabledActiveFg: mediaPlayerInactiveFg;
+	disabledInactiveFg: windowBg;
 	activeOpacity: 1.;
 	inactiveOpacity: 1.;
 	seekSize: size(9px, 9px);
diff --git a/Telegram/SourceFiles/media/player/media_player_cover.cpp b/Telegram/SourceFiles/media/player/media_player_cover.cpp
index ba1bbfe3f..b564fddad 100644
--- a/Telegram/SourceFiles/media/player/media_player_cover.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_cover.cpp
@@ -214,7 +214,11 @@ void CoverWidget::handleSongUpdate(const UpdatedEvent &e) {
 		return;
 	}
 
-	_playback->updateState(*e.playbackState);
+	if (audioId.audio()->loading()) {
+		_playback->updateLoadingState(audioId.audio()->progress());
+	} else {
+		_playback->updateState(*e.playbackState);
+	}
 
 	auto stopped = ((playbackState.state & AudioPlayerStoppedMask) || playbackState.state == AudioPlayerFinishing);
 	auto showPause = !stopped && (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting);
@@ -248,9 +252,7 @@ void CoverWidget::updateTimeText(const AudioMsgId &audioId, const AudioPlaybackS
 	_lastDurationMs = (playbackState.duration * 1000LL) / frequency;
 
 	if (audioId.audio()->loading()) {
-		auto loaded = audioId.audio()->loadOffset();
-		auto loadProgress = snap(float64(loaded) / qMax(audioId.audio()->size, 1), 0., 1.);
-		_time = QString::number(qRound(loadProgress * 100)) + '%';
+		_time = QString::number(qRound(audioId.audio()->progress() * 100)) + '%';
 		_playback->setDisabled(true);
 	} else {
 		display = display / frequency;
diff --git a/Telegram/SourceFiles/media/player/media_player_widget.cpp b/Telegram/SourceFiles/media/player/media_player_widget.cpp
index 348ad4b79..70a6b7619 100644
--- a/Telegram/SourceFiles/media/player/media_player_widget.cpp
+++ b/Telegram/SourceFiles/media/player/media_player_widget.cpp
@@ -267,7 +267,11 @@ void Widget::handleSongUpdate(const UpdatedEvent &e) {
 		return;
 	}
 
-	_playback->updateState(*e.playbackState);
+	if (audioId.audio()->loading()) {
+		_playback->updateLoadingState(audioId.audio()->progress());
+	} else {
+		_playback->updateState(*e.playbackState);
+	}
 
 	auto stopped = ((playbackState.state & AudioPlayerStoppedMask) || playbackState.state == AudioPlayerFinishing);
 	auto showPause = !stopped && (playbackState.state == AudioPlayerPlaying || playbackState.state == AudioPlayerResuming || playbackState.state == AudioPlayerStarting);
@@ -301,9 +305,7 @@ void Widget::updateTimeText(const AudioMsgId &audioId, const AudioPlaybackState
 	_lastDurationMs = (playbackState.duration * 1000LL) / frequency;
 
 	if (audioId.audio()->loading()) {
-		auto loaded = audioId.audio()->loadOffset();
-		auto loadProgress = snap(float64(loaded) / qMax(audioId.audio()->size, 1), 0., 1.);
-		_time = QString::number(qRound(loadProgress * 100)) + '%';
+		_time = QString::number(qRound(audioId.audio()->progress() * 100)) + '%';
 		_playback->setDisabled(true);
 	} else {
 		display = display / frequency;
diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.cpp b/Telegram/SourceFiles/media/view/media_clip_playback.cpp
index 480ff21db..cec0da687 100644
--- a/Telegram/SourceFiles/media/view/media_clip_playback.cpp
+++ b/Telegram/SourceFiles/media/view/media_clip_playback.cpp
@@ -33,6 +33,7 @@ Playback::Playback(Ui::ContinuousSlider *slider) : _slider(slider) {
 void Playback::updateState(const AudioPlaybackState &playbackState) {
 	qint64 position = 0, duration = playbackState.duration;
 
+	setDisabled(false);
 	_playing = !(playbackState.state & AudioPlayerStoppedMask);
 	if (_playing || playbackState.state == AudioPlayerStopped) {
 		position = playbackState.position;
@@ -57,5 +58,11 @@ void Playback::updateState(const AudioPlaybackState &playbackState) {
 	_slider->update();
 }
 
+void Playback::updateLoadingState(float64 progress) {
+	setDisabled(true);
+	auto animated = progress > _slider->value();
+	_slider->setValue(progress, animated);
+}
+
 } // namespace Clip
 } // namespace Media
diff --git a/Telegram/SourceFiles/media/view/media_clip_playback.h b/Telegram/SourceFiles/media/view/media_clip_playback.h
index 2b15cf42f..04689f733 100644
--- a/Telegram/SourceFiles/media/view/media_clip_playback.h
+++ b/Telegram/SourceFiles/media/view/media_clip_playback.h
@@ -32,6 +32,7 @@ public:
 	Playback(Ui::ContinuousSlider *slider);
 
 	void updateState(const AudioPlaybackState &playbackState);
+	void updateLoadingState(float64 progress);
 
 	void setFadeOpacity(float64 opacity) {
 		_slider->setFadeOpacity(opacity);
diff --git a/Telegram/SourceFiles/media/view/mediaview.style b/Telegram/SourceFiles/media/view/mediaview.style
index 99de22070..e2888cc70 100644
--- a/Telegram/SourceFiles/media/view/mediaview.style
+++ b/Telegram/SourceFiles/media/view/mediaview.style
@@ -32,6 +32,8 @@ mediaviewPlayback: MediaSlider {
 	width: 3px;
 	activeFg: mediaviewPlaybackActive;
 	inactiveFg: mediaviewPlaybackInactive;
+	disabledActiveFg: mediaviewPlaybackActive;
+	disabledInactiveFg: mediaviewPlaybackInactive;
 	activeOpacity: mediaviewActiveOpacity;
 	inactiveOpacity: mediaviewInactiveOpacity;
 	seekSize: size(11px, 11px);
diff --git a/Telegram/SourceFiles/mtproto/file_download.cpp b/Telegram/SourceFiles/mtproto/file_download.cpp
index 44531984a..a7836cec9 100644
--- a/Telegram/SourceFiles/mtproto/file_download.cpp
+++ b/Telegram/SourceFiles/mtproto/file_download.cpp
@@ -105,9 +105,9 @@ void FileLoader::readImage(const QSize &shrinkBox) const {
 }
 
 float64 FileLoader::currentProgress() const {
-	if (_complete) return 1;
-	if (!fullSize()) return 0;
-	return float64(currentOffset()) / fullSize();
+	if (_complete) return 1.;
+	if (!fullSize()) return 0.;
+	return snap(float64(currentOffset()) / fullSize(), 0., 1.);
 }
 
 int32 FileLoader::fullSize() const {
diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp
index a41c50b8f..252ce2d62 100644
--- a/Telegram/SourceFiles/structs.cpp
+++ b/Telegram/SourceFiles/structs.cpp
@@ -1368,12 +1368,9 @@ bool DocumentData::displayLoading() const {
 
 float64 DocumentData::progress() const {
 	if (uploading()) {
-		if (size > 0) {
-			return float64(uploadOffset) / size;
-		}
-		return 0;
+		return snap((size > 0) ? float64(uploadOffset) / size : 0., 0., 1.);
 	}
-	return loading() ? _loader->currentProgress() : (loaded() ? 1 : 0);
+	return loading() ? _loader->currentProgress() : (loaded() ? 1. : 0.);
 }
 
 int32 DocumentData::loadOffset() const {
diff --git a/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp b/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp
index abb58c80a..3e5a9a53a 100644
--- a/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp
+++ b/Telegram/SourceFiles/ui/widgets/continuous_slider.cpp
@@ -132,7 +132,7 @@ void ContinuousSlider::wheelEvent(QWheelEvent *e) {
 #else // OS_MAC_OLD
 	constexpr auto step = static_cast<int>(QWheelEvent::DefaultDeltasPerStep);
 #endif // OS_MAC_OLD
-	constexpr auto coef = 1. / (step * 5.);
+	constexpr auto coef = 1. / (step * 10.);
 
 	auto deltaX = e->angleDelta().x(), deltaY = e->angleDelta().y();
 	if (cPlatform() == dbipMac || cPlatform() == dbipMacOld) {
diff --git a/Telegram/SourceFiles/ui/widgets/continuous_slider.h b/Telegram/SourceFiles/ui/widgets/continuous_slider.h
index d2020b98e..a1dac0e40 100644
--- a/Telegram/SourceFiles/ui/widgets/continuous_slider.h
+++ b/Telegram/SourceFiles/ui/widgets/continuous_slider.h
@@ -69,7 +69,7 @@ protected:
 		return _mouseDown ? _downValue : a_value.current();
 	}
 	float64 getCurrentOverFactor(uint64 ms) {
-		return _a_over.current(ms, _over ? 1. : 0.);
+		return _disabled ? 0. : _a_over.current(ms, _over ? 1. : 0.);
 	}
 	bool isDisabled() const {
 		return _disabled;
diff --git a/Telegram/SourceFiles/ui/widgets/filled_slider.cpp b/Telegram/SourceFiles/ui/widgets/filled_slider.cpp
index 83dedadec..c6326c722 100644
--- a/Telegram/SourceFiles/ui/widgets/filled_slider.cpp
+++ b/Telegram/SourceFiles/ui/widgets/filled_slider.cpp
@@ -51,13 +51,13 @@ void FilledSlider::paintEvent(QPaintEvent *e) {
 	auto lineWidthPartial = lineWidth - lineWidthRounded;
 	auto seekRect = getSeekRect();
 	auto value = getCurrentValue(ms);
-	auto from = seekRect.x(), mid = disabled ? from : qRound(from + value * seekRect.width()), end = from + seekRect.width();
+	auto from = seekRect.x(), mid = qRound(from + value * seekRect.width()), end = from + seekRect.width();
 	if (mid > from) {
 		p.setOpacity(masterOpacity);
-		p.fillRect(from, height() - lineWidthRounded, (mid - from), lineWidthRounded, _st.activeFg);
+		p.fillRect(from, height() - lineWidthRounded, (mid - from), lineWidthRounded, disabled ? _st.disabledFg : _st.activeFg);
 		if (lineWidthPartial > 0.01) {
 			p.setOpacity(masterOpacity * lineWidthPartial);
-			p.fillRect(from, height() - lineWidthRounded - 1, (mid - from), 1, _st.activeFg);
+			p.fillRect(from, height() - lineWidthRounded - 1, (mid - from), 1, disabled ? _st.disabledFg : _st.activeFg);
 		}
 	}
 	if (end > mid && over > 0) {
diff --git a/Telegram/SourceFiles/ui/widgets/media_slider.cpp b/Telegram/SourceFiles/ui/widgets/media_slider.cpp
index dacfd2651..43d302eac 100644
--- a/Telegram/SourceFiles/ui/widgets/media_slider.cpp
+++ b/Telegram/SourceFiles/ui/widgets/media_slider.cpp
@@ -60,8 +60,10 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
 	auto markerLength = (horizontal ? seekRect.width() : seekRect.height());
 	auto from = _alwaysDisplayMarker ? 0 : markerFrom;
 	auto length = _alwaysDisplayMarker ? (horizontal ? width() : height()) : markerLength;
-	auto mid = disabled ? from : qRound(from + value * length);
+	auto mid = qRound(from + value * length);
 	auto end = from + length;
+	auto &activeFg = disabled ? _st.disabledActiveFg : _st.activeFg;
+	auto &inactiveFg = disabled ? _st.disabledInactiveFg : _st.inactiveFg;
 	if (mid > from) {
 		auto fromClipRect = horizontal ? QRect(0, 0, mid, height()) : QRect(0, 0, width(), mid);
 		auto fromRect = horizontal
@@ -69,7 +71,7 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
 			: QRect((width() - _st.width) / 2, from, _st.width, mid + radius - from);
 		p.setClipRect(fromClipRect);
 		p.setOpacity(masterOpacity * (over * _st.activeOpacity + (1. - over) * _st.inactiveOpacity));
-		p.setBrush(horizontal ? _st.activeFg : _st.inactiveFg);
+		p.setBrush(horizontal ? activeFg : inactiveFg);
 		p.drawRoundedRect(fromRect, radius, radius);
 	}
 	if (end > mid) {
@@ -79,7 +81,7 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
 			: QRect((width() - _st.width) / 2, mid - radius, _st.width, end - (mid - radius));
 		p.setClipRect(endClipRect);
 		p.setOpacity(masterOpacity);
-		p.setBrush(horizontal ? _st.inactiveFg : _st.activeFg);
+		p.setBrush(horizontal ? inactiveFg : activeFg);
 		p.drawRoundedRect(endRect, radius, radius);
 	}
 	auto markerSizeRatio = disabled ? 0. : (_alwaysDisplayMarker ? 1. : over);
@@ -93,7 +95,7 @@ void MediaSlider::paintEvent(QPaintEvent *e) {
 		if (remove * 2 < size) {
 			p.setClipRect(rect());
 			p.setOpacity(masterOpacity * _st.activeOpacity);
-			p.setBrush(_st.activeFg);
+			p.setBrush(activeFg);
 			p.drawEllipse(seekButton.marginsRemoved(QMargins(remove, remove, remove, remove)));
 		}
 	}
diff --git a/Telegram/SourceFiles/ui/widgets/widgets.style b/Telegram/SourceFiles/ui/widgets/widgets.style
index 636c4e055..3128f0521 100644
--- a/Telegram/SourceFiles/ui/widgets/widgets.style
+++ b/Telegram/SourceFiles/ui/widgets/widgets.style
@@ -37,6 +37,8 @@ MediaSlider {
 	width: pixels;
 	activeFg: color;
 	inactiveFg: color;
+	disabledActiveFg: color;
+	disabledInactiveFg: color;
 	activeOpacity: double;
 	inactiveOpacity: double;
 	seekSize: size;
@@ -48,6 +50,7 @@ FilledSlider {
 	lineWidth: pixels;
 	activeFg: color;
 	inactiveFg: color;
+	disabledFg: color;
 	duration: int;
 }