Improved progress bar popups for downloads

Now shows the filename, and also there's a delay mode where they'll only
be visible if the download takes more than a second, plus they can be
named.
This commit is contained in:
Henrik Rydgård committed 2023-07-18 15:13:44 +02:00
1 parent 04932d98a7
commit ecea3844b0
18 files changed
+167 -157

No files matched your search

+51 -44
View File
@@ -2,6 +2,7 @@
#include "Common/TimeUtil.h"
#include "Common/StringUtils.h"
#include "Common/System/OSD.h"
#ifndef _WIN32
#include <netinet/in.h>
@@ -217,7 +218,7 @@ bool GetHeaderValue(const std::vector<std::string> &responseHeaders, const std::
return found;
}
void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength, float *progress) {
void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength) {
int dechunkedBytes = 0;
while (true) {
std::string line;
@@ -236,14 +237,11 @@ void DeChunk(Buffer *inbuffer, Buffer *outbuffer, int contentLength, float *prog
return;
}
dechunkedBytes += chunkSize;
if (progress && contentLength) {
*progress = (float)dechunkedBytes / contentLength;
}
inbuffer->Skip(2);
}
}
int Client::GET(const RequestParams &req, Buffer *output, std::vector<std::string> &responseHeaders, RequestProgress *progress) {
int Client::GET(const RequestParams &req, Buffer *output, std::vector<std::string> &responseHeaders, net::RequestProgress *progress) {
const char *otherHeaders =
"Accept-Encoding: gzip\r\n";
int err = SendRequest("GET", req, otherHeaders, progress);
@@ -264,13 +262,13 @@ int Client::GET(const RequestParams &req, Buffer *output, std::vector<std::strin
return code;
}
int Client::GET(const RequestParams &req, Buffer *output, RequestProgress *progress) {
int Client::GET(const RequestParams &req, Buffer *output, net::RequestProgress *progress) {
std::vector<std::string> responseHeaders;
int code = GET(req, output, responseHeaders, progress);
return code;
}
int Client::POST(const RequestParams &req, const std::string &data, const std::string &mime, Buffer *output, RequestProgress *progress) {
int Client::POST(const RequestParams &req, const std::string &data, const std::string &mime, Buffer *output, net::RequestProgress *progress) {
char otherHeaders[2048];
if (mime.empty()) {
snprintf(otherHeaders, sizeof(otherHeaders), "Content-Length: %lld\r\n", (long long)data.size());
@@ -296,16 +294,16 @@ int Client::POST(const RequestParams &req, const std::string &data, const std::s
return code;
}
int Client::POST(const RequestParams &req, const std::string &data, Buffer *output, RequestProgress *progress) {
int Client::POST(const RequestParams &req, const std::string &data, Buffer *output, net::RequestProgress *progress) {
return POST(req, data, "", output, progress);
}
int Client::SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, RequestProgress *progress) {
int Client::SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, net::RequestProgress *progress) {
return SendRequestWithData(method, req, "", otherHeaders, progress);
}
int Client::SendRequestWithData(const char *method, const RequestParams &req, const std::string &data, const char *otherHeaders, RequestProgress *progress) {
progress->progress = 0.01f;
int Client::SendRequestWithData(const char *method, const RequestParams &req, const std::string &data, const char *otherHeaders, net::RequestProgress *progress) {
progress->Update(0.01f);
net::Buffer buffer;
const char *tpl =
@@ -331,7 +329,7 @@ int Client::SendRequestWithData(const char *method, const RequestParams &req, co
return 0;
}
int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector<std::string> &responseHeaders, RequestProgress *progress) {
int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector<std::string> &responseHeaders, net::RequestProgress *progress) {
// Snarf all the data we can into RAM. A little unsafe but hey.
static constexpr float CANCEL_INTERVAL = 0.25f;
bool ready = false;
@@ -384,7 +382,7 @@ int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector<std::string> &
return code;
}
int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::string> &responseHeaders, Buffer *output, RequestProgress *progress) {
int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::string> &responseHeaders, Buffer *output, net::RequestProgress *progress) {
bool gzip = false;
bool chunked = false;
int contentLength = 0;
@@ -418,24 +416,19 @@ int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::stri
if (!contentLength) {
// Content length is unknown.
// Set progress to 1% so it looks like something is happening...
progress->progress = 0.1f;
// Set progress to 2% so it looks like something is happening...
// The later progress updates won't include a reliable percentage.
progress->Update(0.02f);
}
if (!contentLength) {
// No way to know how far along we are. Let's just not update the progress counter.
if (!readbuf->ReadAllWithProgress(sock(), contentLength, nullptr, &progress->kBps, progress->cancelled))
return -1;
} else {
// Let's read in chunks, updating progress between each.
if (!readbuf->ReadAllWithProgress(sock(), contentLength, &progress->progress, &progress->kBps, progress->cancelled))
return -1;
}
if (!readbuf->ReadAllWithProgress(sock(), contentLength, progress))
return -1;
// output now contains the rest of the reply. Dechunk it.
if (!output->IsVoid()) {
if (chunked) {
DeChunk(readbuf, output, contentLength, &progress->progress);
DeChunk(readbuf, output, contentLength);
progress->Update(1.0f);
} else {
output->Append(*readbuf);
}
@@ -447,19 +440,39 @@ int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vector<std::stri
bool result = decompress_string(compressed, &decompressed);
if (!result) {
ERROR_LOG(IO, "Error decompressing using zlib");
progress->progress = 0.0f;
progress->Update(0.0f); // TJDO: is this right?
return -1;
}
output->Append(decompressed);
}
}
progress->progress = 1.0f;
progress->Update(1.0f);
return 0;
}
Download::Download(RequestMethod method, const std::string &url, const std::string &postData, const std::string &postMime, const Path &outfile)
: method_(method), progress_(&cancelled_), url_(url), postData_(postData), postMime_(postMime), outfile_(outfile) {
Download::Download(RequestMethod method, const std::string &url, const std::string &postData, const std::string &postMime, const Path &outfile, ProgressBarMode progressBarMode)
: method_(method), progress_(&cancelled_), url_(url), postData_(postData), postMime_(postMime), outfile_(outfile), progressBarMode_(progressBarMode) {
progress_.callback = [=](float progress) {
std::string message;
if (!name_.empty()) {
message = name_;
} else {
std::size_t pos = url.rfind('/');
if (pos != std::string::npos) {
message = url.substr(pos + 1);
} else {
message = url;
}
}
if (progressBarMode_ != ProgressBarMode::NONE) {
g_OSD.SetProgressBar(url, std::move(message), 0.0f, 1.0f, progress, progressBarMode_ == ProgressBarMode::DELAYED ? 1.0f : 0.0f); // delay 0.5 seconds before showing.
if (progress == 1.0f) {
g_OSD.RemoveProgressBar(url, Failed() ? false : true, 0.5f);
}
}
};
}
Download::~Download() {
@@ -480,7 +493,7 @@ void Download::Join() {
void Download::SetFailed(int code) {
failed_ = true;
progress_.progress = 1.0f;
progress_.Update(1.0f);
completed_ = true;
}
@@ -575,15 +588,16 @@ void Download::Do() {
resultCode_ = resultCode;
}
progress_.progress = 1.0f;
progress_.Update(1.0f);
// Set this last to ensure no race conditions when checking Done. Users must always check
// Done before looking at the result code.
completed_ = true;
}
std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, const Path &outfile, const char *acceptMime) {
std::shared_ptr<Download> dl(new Download(RequestMethod::GET, url, "", "", outfile));
std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime) {
std::shared_ptr<Download> dl(new Download(RequestMethod::GET, url, "", "", outfile, mode));
if (!userAgent_.empty())
dl->SetUserAgent(userAgent_);
if (acceptMime)
@@ -596,9 +610,10 @@ std::shared_ptr<Download> Downloader::StartDownload(const std::string &url, cons
std::shared_ptr<Download> Downloader::StartDownloadWithCallback(
const std::string &url,
const Path &outfile,
ProgressBarMode mode,
std::function<void(Download &)> callback,
const char *acceptMime) {
std::shared_ptr<Download> dl(new Download(RequestMethod::GET, url, "", "", outfile));
std::shared_ptr<Download> dl(new Download(RequestMethod::GET, url, "", "", outfile, mode));
if (!userAgent_.empty())
dl->SetUserAgent(userAgent_);
if (acceptMime)
@@ -613,8 +628,9 @@ std::shared_ptr<Download> Downloader::AsyncPostWithCallback(
const std::string &url,
const std::string &postData,
const std::string &postMime,
ProgressBarMode mode,
std::function<void(Download &)> callback) {
std::shared_ptr<Download> dl(new Download(RequestMethod::POST, url, postData, postMime, Path()));
std::shared_ptr<Download> dl(new Download(RequestMethod::POST, url, postData, postMime, Path(), mode));
if (!userAgent_.empty())
dl->SetUserAgent(userAgent_);
dl->SetCallback(callback);
@@ -649,15 +665,6 @@ void Downloader::WaitForAll() {
}
}
std::vector<float> Downloader::GetCurrentProgress() {
std::vector<float> progress;
for (size_t i = 0; i < downloads_.size(); i++) {
if (!downloads_[i]->IsHidden())
progress.push_back(downloads_[i]->Progress());
}
return progress;
}
void Downloader::CancelAll() {
for (size_t i = 0; i < downloads_.size(); i++) {
downloads_[i]->Cancel();