diff --git a/Common/File/PathBrowser.cpp b/Common/File/PathBrowser.cpp index 36e03dca5c..4aba1b41e4 100644 --- a/Common/File/PathBrowser.cpp +++ b/Common/File/PathBrowser.cpp @@ -38,7 +38,7 @@ bool LoadRemoteFileList(const Path &url, const std::string &userAgent, bool *can http::RequestParams req(baseURL.Resource(), "text/plain, text/html; q=0.9, */*; q=0.8"); if (http.Resolve(baseURL.Host().c_str(), baseURL.Port())) { if (http.Connect(2, 20.0, cancel)) { - http::RequestProgress progress(cancel); + net::RequestProgress progress(cancel); code = http.GET(req, &result, responseHeaders, &progress); http.Disconnect(); } diff --git a/Common/Net/HTTPClient.cpp b/Common/Net/HTTPClient.cpp index 74d3784ab7..98c70db433 100644 --- a/Common/Net/HTTPClient.cpp +++ b/Common/Net/HTTPClient.cpp @@ -2,6 +2,7 @@ #include "Common/TimeUtil.h" #include "Common/StringUtils.h" +#include "Common/System/OSD.h" #ifndef _WIN32 #include @@ -217,7 +218,7 @@ bool GetHeaderValue(const std::vector &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 &responseHeaders, RequestProgress *progress) { +int Client::GET(const RequestParams &req, Buffer *output, std::vector &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 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 &responseHeaders, RequestProgress *progress) { +int Client::ReadResponseHeaders(net::Buffer *readbuf, std::vector &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 & return code; } -int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vector &responseHeaders, Buffer *output, RequestProgress *progress) { +int Client::ReadResponseEntity(net::Buffer *readbuf, const std::vector &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::vectorprogress = 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::vectorprogress = 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 Downloader::StartDownload(const std::string &url, const Path &outfile, const char *acceptMime) { - std::shared_ptr dl(new Download(RequestMethod::GET, url, "", "", outfile)); +std::shared_ptr Downloader::StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime) { + std::shared_ptr dl(new Download(RequestMethod::GET, url, "", "", outfile, mode)); + if (!userAgent_.empty()) dl->SetUserAgent(userAgent_); if (acceptMime) @@ -596,9 +610,10 @@ std::shared_ptr Downloader::StartDownload(const std::string &url, cons std::shared_ptr Downloader::StartDownloadWithCallback( const std::string &url, const Path &outfile, + ProgressBarMode mode, std::function callback, const char *acceptMime) { - std::shared_ptr dl(new Download(RequestMethod::GET, url, "", "", outfile)); + std::shared_ptr dl(new Download(RequestMethod::GET, url, "", "", outfile, mode)); if (!userAgent_.empty()) dl->SetUserAgent(userAgent_); if (acceptMime) @@ -613,8 +628,9 @@ std::shared_ptr Downloader::AsyncPostWithCallback( const std::string &url, const std::string &postData, const std::string &postMime, + ProgressBarMode mode, std::function callback) { - std::shared_ptr dl(new Download(RequestMethod::POST, url, postData, postMime, Path())); + std::shared_ptr 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 Downloader::GetCurrentProgress() { - std::vector 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(); diff --git a/Common/Net/HTTPClient.h b/Common/Net/HTTPClient.h index 245eec0ee8..8987e3331e 100644 --- a/Common/Net/HTTPClient.h +++ b/Common/Net/HTTPClient.h @@ -44,16 +44,8 @@ namespace http { bool GetHeaderValue(const std::vector &responseHeaders, const std::string &header, std::string *value); -struct RequestProgress { - RequestProgress() {} - explicit RequestProgress(bool *c) : cancelled(c) {} - - float progress = 0.0f; - float kBps = 0.0f; - bool *cancelled = nullptr; -}; - -struct RequestParams { +class RequestParams { +public: RequestParams() {} explicit RequestParams(const char *r) : resource(r) {} RequestParams(const std::string &r, const char *a) : resource(r), acceptMime(a) {} @@ -68,20 +60,20 @@ public: ~Client(); // Return value is the HTTP return code. 200 means OK. < 0 means some local error. - int GET(const RequestParams &req, Buffer *output, RequestProgress *progress); - int GET(const RequestParams &req, Buffer *output, std::vector &responseHeaders, RequestProgress *progress); + int GET(const RequestParams &req, Buffer *output, net::RequestProgress *progress); + int GET(const RequestParams &req, Buffer *output, std::vector &responseHeaders, net::RequestProgress *progress); // Return value is the HTTP return code. - int POST(const RequestParams &req, const std::string &data, const std::string &mime, Buffer *output, RequestProgress *progress); - int POST(const RequestParams &req, const std::string &data, Buffer *output, RequestProgress *progress); + int POST(const RequestParams &req, const std::string &data, const std::string &mime, Buffer *output, net::RequestProgress *progress); + int POST(const RequestParams &req, const std::string &data, Buffer *output, net::RequestProgress *progress); // HEAD, PUT, DELETE aren't implemented yet, but can be done with SendRequest. - int SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, RequestProgress *progress); - int SendRequestWithData(const char *method, const RequestParams &req, const std::string &data, const char *otherHeaders, RequestProgress *progress); - int ReadResponseHeaders(net::Buffer *readbuf, std::vector &responseHeaders, RequestProgress *progress); + int SendRequest(const char *method, const RequestParams &req, const char *otherHeaders, net::RequestProgress *progress); + int SendRequestWithData(const char *method, const RequestParams &req, const std::string &data, const char *otherHeaders, net::RequestProgress *progress); + int ReadResponseHeaders(net::Buffer *readbuf, std::vector &responseHeaders, net::RequestProgress *progress); // If your response contains a response, you must read it. - int ReadResponseEntity(net::Buffer *readbuf, const std::vector &responseHeaders, Buffer *output, RequestProgress *progress); + int ReadResponseEntity(net::Buffer *readbuf, const std::vector &responseHeaders, Buffer *output, net::RequestProgress *progress); void SetDataTimeout(double t) { dataTimeout_ = t; @@ -102,12 +94,26 @@ enum class RequestMethod { POST, }; +enum class ProgressBarMode { + NONE, + VISIBLE, + DELAYED, +}; + // Really an asynchronous request. class Download { public: - Download(RequestMethod method, const std::string &url, const std::string &postData, const std::string &postMime, const Path &outfile); + Download(RequestMethod method, const std::string &url, const std::string &postData, const std::string &postMime, const Path &outfile, ProgressBarMode progressBarMode = ProgressBarMode::DELAYED); ~Download(); + void SetAccept(const char *mime) { + acceptMime_ = mime; + } + + void SetUserAgent(const std::string &userAgent) { + userAgent_ = userAgent; + } + void Start(); void Join(); @@ -125,10 +131,6 @@ public: std::string url() const { return url_; } const Path &outfile() const { return outfile_; } - void SetAccept(const char *mime) { - acceptMime_ = mime; - } - // If not downloading to a file, access this to get the result. Buffer &buffer() { return buffer_; } const Buffer &buffer() const { return buffer_; } @@ -141,7 +143,7 @@ public: return cancelled_; } - // NOTE: Callbacks are NOT executed until RunCallback is called. This is so that + // NOTE: Completion callbacks (which these are) are deferred until RunCallback is called. This is so that // the call will end up on the thread that calls g_DownloadManager.Update(). void SetCallback(std::function callback) { callback_ = callback; @@ -151,14 +153,8 @@ public: callback_(*this); } } - - // Just metadata. Convenient for download managers, for example, if set, - // Downloader::GetCurrentProgress won't return it in the results. - bool IsHidden() const { return hidden_; } - void SetHidden(bool hidden) { hidden_ = hidden; } - void SetUserAgent(const std::string &userAgent) { - userAgent_ = userAgent; - } + // Visual name for the download, to be displayed in progress bars. + void SetName(const std::string &&name) { name_ = std::move(name); } private: void Do(); // Actually does the download. Runs on thread. @@ -166,8 +162,8 @@ private: std::string RedirectLocation(const std::string &baseUrl); void SetFailed(int code); - RequestProgress progress_; RequestMethod method_; + net::RequestProgress progress_; std::string postData_; std::string userAgent_; Buffer buffer_; @@ -181,8 +177,9 @@ private: bool completed_ = false; bool failed_ = false; bool cancelled_ = false; - bool hidden_ = false; + ProgressBarMode progressBarMode_; bool joined_ = false; + std::string name_; std::function callback_; }; @@ -194,11 +191,12 @@ public: CancelAll(); } - std::shared_ptr StartDownload(const std::string &url, const Path &outfile, const char *acceptMime = nullptr); + std::shared_ptr StartDownload(const std::string &url, const Path &outfile, ProgressBarMode mode, const char *acceptMime = nullptr); std::shared_ptr StartDownloadWithCallback( const std::string &url, const Path &outfile, + ProgressBarMode mode, std::function callback, const char *acceptMime = nullptr); @@ -206,6 +204,7 @@ public: const std::string &url, const std::string &postData, const std::string &postMime, // Use postMime = "application/x-www-form-urlencoded" for standard form-style posts, such as used by retroachievements. For encoding form data manually we have MultipartFormDataEncoder. + ProgressBarMode mode, std::function callback); // Drops finished downloads from the list. @@ -217,12 +216,6 @@ public: userAgent_ = userAgent; } - std::vector GetCurrentProgress(); - - size_t GetActiveCount() const { - return downloads_.size(); - } - private: std::vector> downloads_; // These get copied to downloads_ in Update(). It's so that callbacks can add new downloads diff --git a/Common/Net/NetBuffer.cpp b/Common/Net/NetBuffer.cpp index 17a5aae916..cf2f16706c 100644 --- a/Common/Net/NetBuffer.cpp +++ b/Common/Net/NetBuffer.cpp @@ -48,7 +48,7 @@ bool Buffer::FlushSocket(uintptr_t sock, double timeout, bool *cancelled) { return true; } -bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress, float *kBps, bool *cancelled) { +bool Buffer::ReadAllWithProgress(int fd, int knownSize, RequestProgress *progress) { static constexpr float CANCEL_INTERVAL = 0.25f; std::vector buf; // We're non-blocking and reading from an OS buffer, so try to read as much as we can at a time. @@ -64,8 +64,8 @@ bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress, float * int total = 0; while (true) { bool ready = false; - while (!ready && cancelled) { - if (*cancelled) + while (!ready && (!progress || !*progress->cancelled)) { + if (*progress->cancelled) return false; ready = fd_util::WaitUntilReady(fd, CANCEL_INTERVAL, false); } @@ -88,10 +88,10 @@ bool Buffer::ReadAllWithProgress(int fd, int knownSize, float *progress, float * char *p = Append((size_t)retval); memcpy(p, &buf[0], retval); total += retval; - if (progress) - *progress = (float)total / (float)knownSize; - if (kBps) - *kBps = (float)(total / (time_now_d() - st)) / 1024.0f; + if (progress) { + progress->Update((float)total / (float)knownSize); + progress->kBps = (float)(total / (time_now_d() - st)) / 1024.0f; + } } return true; } @@ -114,4 +114,4 @@ int Buffer::Read(int fd, size_t sz) { return (int)received; } -} +} // namespace diff --git a/Common/Net/NetBuffer.h b/Common/Net/NetBuffer.h index 12a4ba37c8..bc49b97ab4 100644 --- a/Common/Net/NetBuffer.h +++ b/Common/Net/NetBuffer.h @@ -1,16 +1,35 @@ -#pragma once +#pragma once #include +#include #include "Common/Buffer.h" namespace net { +class RequestProgress { +public: + RequestProgress() {} + explicit RequestProgress(bool *c) : cancelled(c) {} + + void Update(float newProgress) { + progress = newProgress; + if (callback) { + callback(newProgress); + } + } + + float progress = 0.0f; + float kBps = 0.0f; + bool *cancelled = nullptr; + std::function callback; +}; + class Buffer : public ::Buffer { public: bool FlushSocket(uintptr_t sock, double timeout, bool *cancelled = nullptr); - bool ReadAllWithProgress(int fd, int knownSize, float *progress, float *kBps, bool *cancelled); + bool ReadAllWithProgress(int fd, int knownSize, RequestProgress *progress); // < 0: error // >= 0: number of bytes read diff --git a/Common/System/OSD.cpp b/Common/System/OSD.cpp index fd85dde9ca..f100737cc8 100644 --- a/Common/System/OSD.cpp +++ b/Common/System/OSD.cpp @@ -215,7 +215,7 @@ void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float durat Show(OSDType::MESSAGE_INFO, message + ": " + (on ? "on" : "off"), duration_s); } -void OnScreenDisplay::SetProgressBar(std::string id, std::string &&message, int minValue, int maxValue, int progress) { +void OnScreenDisplay::SetProgressBar(std::string id, std::string &&message, float minValue, float maxValue, float progress, float delay) { std::lock_guard guard(mutex_); double now = time_now_d(); bool found = false; @@ -236,16 +236,27 @@ void OnScreenDisplay::SetProgressBar(std::string id, std::string &&message, int bar.minValue = minValue; bar.maxValue = maxValue; bar.progress = progress; + bar.startTime = now + delay; bar.endTime = now + 60.0; // Show the progress bar for 60 seconds, then fade it out. bars_.push_back(bar); } -void OnScreenDisplay::RemoveProgressBar(std::string id) { +void OnScreenDisplay::RemoveProgressBar(std::string id, bool success, float delay_s) { std::lock_guard guard(mutex_); for (auto iter = bars_.begin(); iter != bars_.end(); iter++) { if (iter->id == id) { - iter->progress = iter->maxValue; - iter->endTime = time_now_d() + FadeoutTime(); + if (success) { + // Quickly shoot up to max, if we weren't there. + if (iter->maxValue != 0.0f) { + iter->progress = iter->maxValue; + } else { + // Fake a full progress + iter->minValue = 0; + iter->maxValue = 1; + iter->progress = 1; + } + } + iter->endTime = time_now_d() + delay_s + FadeoutTime(); break; } } diff --git a/Common/System/OSD.h b/Common/System/OSD.h index 928e1d44d6..6432cca01c 100644 --- a/Common/System/OSD.h +++ b/Common/System/OSD.h @@ -50,8 +50,8 @@ public: // Progress bar controls // Set is both create and update. If you set maxValue <= minValue, you'll create an "indeterminate" progress // bar that doesn't show a specific amount of progress. - void SetProgressBar(std::string id, std::string &&message, int minValue, int maxValue, int progress); - void RemoveProgressBar(std::string id); + void SetProgressBar(std::string id, std::string &&message, float minValue, float maxValue, float progress, float delay_s); + void RemoveProgressBar(std::string id, bool success, float delay_s); // Call every frame to keep the sidebar visible. Otherwise it'll fade out. void NudgeSidebar(); @@ -74,9 +74,10 @@ public: struct ProgressBar { std::string id; std::string message; - int minValue; - int maxValue; - int progress; + float minValue; + float maxValue; + float progress; + double startTime; double endTime; }; diff --git a/Core/Config.cpp b/Core/Config.cpp index 030d828fda..316157d3e5 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1174,8 +1174,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { if (iRunCount % 10 == 0 && bCheckForNewVersion) { const char *versionUrl = "http://www.ppsspp.org/version.json"; const char *acceptMime = "application/json, text/*; q=0.9, */*; q=0.8"; - auto dl = g_DownloadManager.StartDownloadWithCallback(versionUrl, Path(), &DownloadCompletedCallback, acceptMime); - dl->SetHidden(true); + g_DownloadManager.StartDownloadWithCallback(versionUrl, Path(), http::ProgressBarMode::NONE, &DownloadCompletedCallback, acceptMime); } INFO_LOG(LOADER, "Loading controller config: %s", controllerIniFilename_.c_str()); diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index ec92b8b9d5..e4bf8ee9be 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -71,7 +71,7 @@ private: s64 filepos_ = 0; Url url_; http::Client client_; - http::RequestProgress progress_; + net::RequestProgress progress_; ::Path filename_; bool connected_ = false; bool cancel_ = false; diff --git a/Core/HLE/sceNp2.cpp b/Core/HLE/sceNp2.cpp index 59f7b0cfdf..89f047757f 100644 --- a/Core/HLE/sceNp2.cpp +++ b/Core/HLE/sceNp2.cpp @@ -131,7 +131,7 @@ static int sceNpMatching2ContextStart(int ctxId) //npMatching2Ctx.started = true; Url url("http://static-resource.np.community.playstation.net/np/resource/psp-title/" + std::string(npTitleId.data) + "_00/matching/" + std::string(npTitleId.data) + "_00-matching.xml"); http::Client client; - http::RequestProgress progress; + net::RequestProgress progress; if (!client.Resolve(url.Host().c_str(), url.Port())) { return hleLogError(SCENET, SCE_NP_COMMUNITY_SERVER_ERROR_NO_SUCH_TITLE, "HTTP failed to resolve %s", url.Resource().c_str()); } diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index bedcbf8d85..df6c7a84f5 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -272,7 +272,7 @@ namespace Reporting bool SendReportRequest(const char *uri, const std::string &data, const std::string &mimeType, Buffer *output = NULL) { http::Client http; - http::RequestProgress progress(&pendingMessagesDone); + net::RequestProgress progress(&pendingMessagesDone); Buffer theVoid = Buffer::Void(); http.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); diff --git a/Core/RetroAchievements.cpp b/Core/RetroAchievements.cpp index 97ec1efcd8..84710d136a 100644 --- a/Core/RetroAchievements.cpp +++ b/Core/RetroAchievements.cpp @@ -176,7 +176,7 @@ static void server_call_callback(const rc_api_request_t *request, { // If post data is provided, we need to make a POST request, otherwise, a GET request will suffice. if (request->post_data) { - g_DownloadManager.AsyncPostWithCallback(std::string(request->url), std::string(request->post_data), "application/x-www-form-urlencoded", [=](http::Download &download) { + g_DownloadManager.AsyncPostWithCallback(std::string(request->url), std::string(request->post_data), "application/x-www-form-urlencoded", http::ProgressBarMode::DELAYED, [=](http::Download &download) { std::string buffer; download.buffer().TakeAll(&buffer); rc_api_server_response_t response{}; @@ -186,7 +186,7 @@ static void server_call_callback(const rc_api_request_t *request, callback(&response, callback_data); }); } else { - g_DownloadManager.StartDownloadWithCallback(std::string(request->url), Path(), [=](http::Download &download) { + g_DownloadManager.StartDownloadWithCallback(std::string(request->url), Path(), http::ProgressBarMode::DELAYED, [=](http::Download &download) { std::string buffer; download.buffer().TakeAll(&buffer); rc_api_server_response_t response{}; @@ -394,7 +394,7 @@ static void login_password_callback(int result, const char *error_message, rc_cl } } - g_OSD.RemoveProgressBar("cheevos_async_login"); + g_OSD.RemoveProgressBar("cheevos_async_login", true, 0.1f); g_isLoggingIn = false; } @@ -403,7 +403,7 @@ bool LoginAsync(const char *username, const char *password) { if (IsLoggedIn() || std::strlen(username) == 0 || std::strlen(password) == 0 || IsUsingRAIntegration()) return false; - g_OSD.SetProgressBar("cheevos_async_login", di->T("Logging in..."), 0, 0, 0); + g_OSD.SetProgressBar("cheevos_async_login", di->T("Logging in..."), 0, 0, 0, 0.0f); g_isLoggingIn = true; rc_client_begin_login_with_password(g_rcClient, username, password, &login_password_callback, nullptr); @@ -540,7 +540,7 @@ bool HasAchievementsOrLeaderboards() { void DownloadImageIfMissing(const std::string &cache_key, std::string &&url) { if (g_iconCache.MarkPending(cache_key)) { INFO_LOG(ACHIEVEMENTS, "Downloading image: %s (%s)", url.c_str(), cache_key.c_str()); - g_DownloadManager.StartDownloadWithCallback(url, Path(), [cache_key](http::Download &download) { + g_DownloadManager.StartDownloadWithCallback(url, Path(), http::ProgressBarMode::NONE, [cache_key](http::Download &download) { if (download.ResultCode() != 200) return; std::string data; diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index 37b3b1dd6a..c8e09e4ab8 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -102,7 +102,7 @@ bool GameManager::DownloadAndInstall(std::string storeFileUrl) { Path filename = GetTempFilename(); const char *acceptMime = "application/zip, application/x-cso, application/x-iso9660-image, application/octet-stream; q=0.9, */*; q=0.8"; - curDownload_ = g_DownloadManager.StartDownload(storeFileUrl, filename, acceptMime); + curDownload_ = g_DownloadManager.StartDownload(storeFileUrl, filename, http::ProgressBarMode::VISIBLE, acceptMime); return true; } diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp index 9db7b0f5fd..c530fdb83d 100644 --- a/Core/WebServer.cpp +++ b/Core/WebServer.cpp @@ -64,7 +64,7 @@ static ServerStatus RetrieveStatus() { static bool RegisterServer(int port) { bool success = false; http::Client http; - http::RequestProgress progress; + net::RequestProgress progress; Buffer theVoid = Buffer::Void(); http.SetUserAgent(StringFromFormat("PPSSPP/%s", PPSSPP_GIT_VERSION)); diff --git a/UI/DevScreens.cpp b/UI/DevScreens.cpp index 17169f6ed2..6c7e336ad3 100644 --- a/UI/DevScreens.cpp +++ b/UI/DevScreens.cpp @@ -819,19 +819,23 @@ void SystemInfoScreen::CreateTabs() { }); internals->Add(new ItemHeader(si->T("Progress tests"))); internals->Add(new Choice(si->T("30%")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.SetProgressBar("testprogress", "Test Progress", 1, 100, 30); + g_OSD.SetProgressBar("testprogress", "Test Progress", 1, 100, 30, 0.0f); return UI::EVENT_DONE; }); internals->Add(new Choice(si->T("100%")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.SetProgressBar("testprogress", "Test Progress", 1, 100, 100); + g_OSD.SetProgressBar("testprogress", "Test Progress", 1, 100, 100, 1.0f); return UI::EVENT_DONE; }); internals->Add(new Choice(si->T("N/A%")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.SetProgressBar("testprogress", "Test Progress", 0, 0, 0); + g_OSD.SetProgressBar("testprogress", "Test Progress", 0, 0, 0, 0.0f); return UI::EVENT_DONE; }); - internals->Add(new Choice(si->T("Clear")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.RemoveProgressBar("testprogress"); + internals->Add(new Choice(si->T("Success")))->OnClick.Add([&](UI::EventParams &) { + g_OSD.RemoveProgressBar("testprogress", true, 0.5f); + return UI::EVENT_DONE; + }); + internals->Add(new Choice(si->T("Failure")))->OnClick.Add([&](UI::EventParams &) { + g_OSD.RemoveProgressBar("testprogress", false, 0.5f); return UI::EVENT_DONE; }); internals->Add(new ItemHeader(si->T("Achievement tests"))); @@ -1336,7 +1340,7 @@ void FrameDumpTestScreen::update() { if (!listing_) { const char *acceptMime = "text/html, */*; q=0.8"; - listing_ = g_DownloadManager.StartDownload(framedumpsBaseUrl, Path(), acceptMime); + listing_ = g_DownloadManager.StartDownload(framedumpsBaseUrl, Path(), http::ProgressBarMode::DELAYED, acceptMime); } if (listing_ && listing_->Done() && files_.empty()) { diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index fec95d5365..7d5b2a0ee0 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -292,13 +292,9 @@ void OnScreenMessagesView::Draw(UIContext &dc) { } } - // Get height - float w, h; - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, "Wg", &w, &h); - y = 10.0f; - // Then draw them all. + // Draw the progress bars. const std::vector bars = g_OSD.ProgressBars(); for (auto &bar : bars) { float tw, th; @@ -306,11 +302,14 @@ void OnScreenMessagesView::Draw(UIContext &dc) { Bounds b(0.0f, y, tw, th); b.x = (bounds_.w - b.w) * 0.5f; - float alpha = Clamp((float)(bar.endTime - now) * 4.0f, 0.0f, 1.0f); + float enterAlpha = saturatef((float)(now - bar.startTime) * 4.0f); + float leaveAlpha = saturatef((float)(bar.endTime - now) * 4.0f); + float alpha = std::min(enterAlpha, leaveAlpha); RenderOSDProgressBar(dc, bar, b, 0, alpha); y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations. } + // Draw the rest of the top-center messages. const std::vector entries = g_OSD.Entries(); for (const auto &entry : entries) { dc.SetFontScale(1.0f, 1.0f); @@ -365,28 +364,6 @@ void OnScreenMessagesView::Draw(UIContext &dc) { RenderOSDEntry(dc, entry, b, h1, align, alpha); y += (b.h * scale + 4.0f) * alpha; // including alpha here gets us smooth animations. } - - // Thin bar at the top of the screen. - // TODO: Remove and replace with "proper" progress bars. - std::vector progress = g_DownloadManager.GetCurrentProgress(); - if (!progress.empty()) { - static const uint32_t colors[4] = { - 0xFFFFFFFF, - 0xFFCCCCCC, - 0xFFAAAAAA, - 0xFF777777, - }; - - dc.Begin(); - int h = 5; - for (size_t i = 0; i < progress.size(); i++) { - float barWidth = 10 + (dc.GetBounds().w - 10) * progress[i]; - Bounds bounds(0, h * i, barWidth, h); - UI::Drawable solid(colors[i & 3]); - dc.FillRect(solid, bounds); - } - dc.Flush(); - } } std::string OnScreenMessagesView::DescribeText() const { diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 5436750cc5..b80df30021 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -139,7 +139,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort } SetStatus("Loading game list from [URL]...", host, port); - http::RequestProgress progress(&scanCancelled); + net::RequestProgress progress(&scanCancelled); code = http.GET(http::RequestParams(subdir.c_str()), &result, &progress); http.Disconnect(); @@ -193,7 +193,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort SetStatus("Looking for peers...", "", 0); if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) { if (http.Connect(2, 20.0, &scanCancelled)) { - http::RequestProgress progress(&scanCancelled); + net::RequestProgress progress(&scanCancelled); code = http.GET(http::RequestParams("/match/list"), &result, &progress); http.Disconnect(); } diff --git a/UI/Store.cpp b/UI/Store.cpp index 2682b171cb..0ad19143f6 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -58,7 +58,7 @@ public: if (useIconCache && g_iconCache.MarkPending(path_)) { const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8"; - downloader_->StartDownloadWithCallback(path_, Path(), [&](http::Download &download) { + downloader_->StartDownloadWithCallback(path_, Path(), http::ProgressBarMode::DELAYED, [&](http::Download &download) { if (download.ResultCode() == 200) { std::string data; download.buffer().TakeAll(&data); @@ -165,8 +165,7 @@ void HttpImageFileView::Draw(UIContext &dc) { if (!texture_ && !textureFailed_ && !path_.empty() && !download_) { auto cb = std::bind(&HttpImageFileView::DownloadCompletedCallback, this, std::placeholders::_1); const char *acceptMime = "image/png, image/jpeg, image/*; q=0.9, */*; q=0.8"; - download_ = downloader_->StartDownloadWithCallback(path_, Path(), cb, acceptMime); - download_->SetHidden(true); + downloader_->StartDownloadWithCallback(path_, Path(), http::ProgressBarMode::NONE, cb, acceptMime); } if (!textureData_.empty()) { @@ -404,7 +403,7 @@ StoreScreen::StoreScreen() { std::string indexPath = storeBaseUrl + "index.json"; const char *acceptMime = "application/json, */*; q=0.8"; - listing_ = g_DownloadManager.StartDownload(indexPath, Path(), acceptMime); + listing_ = g_DownloadManager.StartDownload(indexPath, Path(), http::ProgressBarMode::DELAYED, acceptMime); } StoreScreen::~StoreScreen() {