simple visual progress bar (#7)

* download files directly to sd instead of a buffer

- this fixes running out of memory while downloading large files

* simple visual download progressbar
This commit is contained in:
Stefan Schnitzler
2019-11-17 02:30:30 +01:00
committed by VoltZ
parent 3e626f1046
commit 99e09bd17c
4 changed files with 789 additions and 727 deletions
+3
View File
@@ -0,0 +1,3 @@
#pragma once
std::string formatBytes(int bytes);
+59 -3
View File
@@ -36,10 +36,12 @@
#include "utils/extract.hpp" #include "utils/extract.hpp"
#include "utils/fileBrowse.h" #include "utils/fileBrowse.h"
#include "utils/thread.hpp" #include "utils/thread.hpp"
#include "utils/formatting.hpp"
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include <vector> #include <vector>
#include <string>
extern "C" { extern "C" {
#include "utils/cia.h" #include "utils/cia.h"
@@ -62,6 +64,10 @@ char progressBarMsg[128] = "";
bool showProgressBar = false; bool showProgressBar = false;
bool progressBarType = 0; // 0 = Download | 1 = Extract bool progressBarType = 0; // 0 = Download | 1 = Extract
#define TIME_IN_US 1
#define TIMETYPE curl_off_t
#define TIMEOPT CURLINFO_TOTAL_TIME_T
#define MINIMAL_PROGRESS_FUNCTIONALITY_INTERVAL 3000000
// following function is from // following function is from
// https://github.com/angelsl/libctrfgh/blob/master/curl_test/src/main.c // https://github.com/angelsl/libctrfgh/blob/master/curl_test/src/main.c
@@ -115,11 +121,28 @@ static size_t handle_data_to_file(char* ptr, size_t size, size_t nmemb, void* us
return bsz; return bsz;
} }
curl_off_t downloadTotal = 1; //Dont initialize with 0 to avoid division by zero later
curl_off_t downloadNow = 0;
static int curlProgress(CURL *hnd,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
downloadTotal = dltotal;
downloadNow = dlnow;
return 0;
}
static Result setupContext(CURL *hnd, const char * url) static Result setupContext(CURL *hnd, const char * url)
{ {
downloadTotal = 1;
downloadNow = 0;
curl_easy_setopt(hnd, CURLOPT_XFERINFOFUNCTION, curlProgress);
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L); curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, url); curl_easy_setopt(hnd, CURLOPT_URL, url);
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L); curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, USER_AGENT); curl_easy_setopt(hnd, CURLOPT_USERAGENT, USER_AGENT);
curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(hnd, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L); curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
@@ -646,11 +669,44 @@ void downloadTheme(std::string path) {
} }
} }
void displayProgressBar() { void displayProgressBar() {
char str[256]; char str[256];
while(showProgressBar) { while(showProgressBar) {
snprintf(str, sizeof(str), "%s\n%s%s\n%i %s", progressBarMsg, (!progressBarType ? "" : (Lang::get("CURRENTLY_EXTRACTING")).c_str()), (!progressBarType ? "" : extractingFile.c_str()), (!progressBarType ? (int)round(result_written/1000) : filesExtracted), (!progressBarType ? (Lang::get("KB_DOWNLOADED")).c_str() : (filesExtracted == 1 ? (Lang::get("FILE_EXTRACTED")).c_str() :(Lang::get("FILES_EXTRACTED")).c_str()))); if (downloadTotal < 1.0f) {
DisplayMsg(str); downloadTotal = 1.0f;
}
if (downloadTotal < downloadNow) {
downloadTotal = downloadNow;
}
if (progressBarType) {
snprintf(str, sizeof(str), "%i %s",
filesExtracted,
(filesExtracted == 1 ? (Lang::get("FILE_EXTRACTED")).c_str() :(Lang::get("FILES_EXTRACTED")).c_str())
);
} else {
snprintf(str, sizeof(str), "%s / %s (%.2f%%)",
formatBytes(downloadNow).c_str(),
formatBytes(downloadTotal).c_str(),
((float)downloadNow/(float)downloadTotal) * 100.0f
);
}
Gui::clearTextBufs();
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
C2D_TargetClear(top, BLACK);
C2D_TargetClear(bottom, BLACK);
Gui::DrawTop();
Gui::DrawStringCentered(0, 2, 0.7f, Config::TxtColor, progressBarMsg, 400);
Gui::DrawStringCentered(0, 80, 0.6f, Config::TxtColor, str, 400);
Gui::Draw_Rect(30, 120, 340, 30, BLACK);
Gui::Draw_Rect(31, 121, (int)(((float)downloadNow/(float)downloadTotal) * 338.0f), 28, WHITE);
Gui::DrawBottom();
C3D_FrameEnd(0);
//DisplayMsg(str);
gspWaitForVBlank(); gspWaitForVBlank();
} }
} }
+2 -18
View File
@@ -31,6 +31,7 @@
#include "utils/config.hpp" #include "utils/config.hpp"
#include "utils/fileBrowse.h" #include "utils/fileBrowse.h"
#include "utils/json.hpp" #include "utils/json.hpp"
#include "utils/formatting.hpp"
#define ENTRIES_PER_SCREEN 3 #define ENTRIES_PER_SCREEN 3
#define ENTRIES_PER_LIST 7 #define ENTRIES_PER_LIST 7
@@ -66,23 +67,6 @@ std::vector<std::string> parseObjects() {
std::vector<std::string> tinyDBList; std::vector<std::string> tinyDBList;
// adapted from GM9i's byte parsing.
std::string parseBytes(int bytes) {
char out[32];
if(bytes == 1)
snprintf(out, sizeof(out), "%d Byte", bytes);
else if(bytes < 1024)
snprintf(out, sizeof(out), "%d Bytes", bytes);
else if(bytes < 1024 * 1024)
snprintf(out, sizeof(out), "%.1f KB", (float)bytes / 1024);
else if (bytes < 1024 * 1024 * 1024)
snprintf(out, sizeof(out), "%.1f MB", (float)bytes / 1024 / 1024);
else
snprintf(out, sizeof(out), "%.1f GB", (float)bytes / 1024 / 1024 / 1024);
return out;
}
TinyDB::TinyDB() { TinyDB::TinyDB() {
DisplayMsg(Lang::get("TINYDB_DOWNLOADING")); DisplayMsg(Lang::get("TINYDB_DOWNLOADING"));
downloadToFile("https://tinydb.eiphax.tech/api/universal-updater.json?raw=true", tinyDBFile); downloadToFile("https://tinydb.eiphax.tech/api/universal-updater.json?raw=true", tinyDBFile);
@@ -103,7 +87,7 @@ void TinyDB::Draw(void) const {
Gui::DrawStringCentered(0, 95, 0.6f, Config::TxtColor, Lang::get("RELEASE_TAG") + std::string(tinyDBJson[selectedOption]["info"]["releaseTag"]), 400); Gui::DrawStringCentered(0, 95, 0.6f, Config::TxtColor, Lang::get("RELEASE_TAG") + std::string(tinyDBJson[selectedOption]["info"]["releaseTag"]), 400);
Gui::DrawStringCentered(0, 125, 0.6f, Config::TxtColor, Lang::get("RELEASE_ID") + std::string(tinyDBJson[selectedOption]["info"]["releaseId"]), 400); Gui::DrawStringCentered(0, 125, 0.6f, Config::TxtColor, Lang::get("RELEASE_ID") + std::string(tinyDBJson[selectedOption]["info"]["releaseId"]), 400);
Gui::DrawStringCentered(0, 155, 0.6f, Config::TxtColor, Lang::get("TITLE_ID") + std::string(tinyDBJson[selectedOption]["info"]["titleid"]), 400); Gui::DrawStringCentered(0, 155, 0.6f, Config::TxtColor, Lang::get("TITLE_ID") + std::string(tinyDBJson[selectedOption]["info"]["titleid"]), 400);
Gui::DrawStringCentered(0, 185, 0.6f, Config::TxtColor, Lang::get("FILE_SIZE") + parseBytes(int64_t(tinyDBJson[selectedOption]["info"]["fileSize"])), 400); Gui::DrawStringCentered(0, 185, 0.6f, Config::TxtColor, Lang::get("FILE_SIZE") + formatBytes(int64_t(tinyDBJson[selectedOption]["info"]["fileSize"])), 400);
Gui::DrawStringCentered(0, 2, 0.7f, Config::TxtColor, "TinyDB", 400); Gui::DrawStringCentered(0, 2, 0.7f, Config::TxtColor, "TinyDB", 400);
std::string entryAmount = std::to_string(selection+1) + " / " + std::to_string(tinyDBList.size()); std::string entryAmount = std::to_string(selection+1) + " / " + std::to_string(tinyDBList.size());
Gui::DrawString(397-Gui::GetStringWidth(0.6f, entryAmount), 237-Gui::GetStringHeight(0.6f, entryAmount), 0.6f, Config::TxtColor, entryAmount); Gui::DrawString(397-Gui::GetStringWidth(0.6f, entryAmount), 237-Gui::GetStringHeight(0.6f, entryAmount), 0.6f, Config::TxtColor, entryAmount);
+19
View File
@@ -0,0 +1,19 @@
#include <string>
#include "utils/formatting.hpp"
// adapted from GM9i's byte parsing.
std::string formatBytes(int bytes) {
char out[32];
if(bytes == 1)
snprintf(out, sizeof(out), "%d Byte", bytes);
else if(bytes < 1024)
snprintf(out, sizeof(out), "%d Bytes", bytes);
else if(bytes < 1024 * 1024)
snprintf(out, sizeof(out), "%.1f KB", (float)bytes / 1024);
else if (bytes < 1024 * 1024 * 1024)
snprintf(out, sizeof(out), "%.1f MB", (float)bytes / 1024 / 1024);
else
snprintf(out, sizeof(out), "%.1f GB", (float)bytes / 1024 / 1024 / 1024);
return out;
}