Unified DLS+ETA progress labels and implemented ETA tracking for extraction, installation, and copy operations
- Removed separate DLS+ETA labels, unified into a clearer single label - Repositioned and resized that label slightly to avoid top of label getting cut off - Added guards to prevent brief progress bar flashes during multi-file downloads - Added ETA for file extraction, APK installation, and OBB copy operations by tracking elapsed time and calculating a smoothed ETA based on the rate of progress
This commit is contained in:
194
MainForm.cs
194
MainForm.cs
@@ -401,7 +401,6 @@ namespace AndroidSideloader
|
||||
gamesListView.View = View.Details;
|
||||
gamesListView.FullRowSelect = true;
|
||||
gamesListView.GridLines = false;
|
||||
etaLabel.Text = String.Empty;
|
||||
speedLabel.Text = String.Empty;
|
||||
diskLabel.Text = String.Empty;
|
||||
|
||||
@@ -965,24 +964,26 @@ namespace AndroidSideloader
|
||||
|
||||
output = await ADB.CopyOBBWithProgressAsync(
|
||||
path,
|
||||
progress => this.Invoke(() => {
|
||||
(progress, eta) => this.Invoke(() => {
|
||||
progressBar.Value = progress;
|
||||
speedLabel.Text = $"Progress: {progress}%";
|
||||
string etaStr = eta.HasValue && eta.Value.TotalSeconds > 0
|
||||
? $" · ETA: {eta.Value:mm\\:ss}"
|
||||
: "";
|
||||
speedLabel.Text = $"Progress: {progress}%{etaStr}";
|
||||
}),
|
||||
status => this.Invoke(() => {
|
||||
progressBar.StatusText = status;
|
||||
etaLabel.Text = status;
|
||||
}),
|
||||
folderName);
|
||||
|
||||
progressBar.Value = 100;
|
||||
progressBar.StatusText = "";
|
||||
changeTitle("Done.");
|
||||
showAvailableSpace();
|
||||
|
||||
ShowPrcOutput(output);
|
||||
changeTitle("");
|
||||
speedLabel.Text = "";
|
||||
etaLabel.Text = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3047,7 +3048,6 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
public async void cleanupActiveDownloadStatus()
|
||||
{
|
||||
speedLabel.Text = String.Empty;
|
||||
etaLabel.Text = String.Empty;
|
||||
progressBar.Value = 0;
|
||||
gamesQueueList.RemoveAt(0);
|
||||
}
|
||||
@@ -3262,16 +3262,17 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
|
||||
changeTitle("Downloading game " + gameName);
|
||||
speedLabel.Text = "Starting download...";
|
||||
etaLabel.Text = "Please wait...";
|
||||
|
||||
//Download
|
||||
// Track the highest valid progress to prevent brief progress bar flashes during multi-file transfers
|
||||
int highestValidPercent = 0;
|
||||
|
||||
// Download
|
||||
while (t1.IsAlive)
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await client.PostAsync("http://127.0.0.1:5572/core/stats", null);
|
||||
string foo = await response.Content.ReadAsStringAsync();
|
||||
//Debug.WriteLine("RESP CONTENT " + foo);
|
||||
dynamic results = JsonConvert.DeserializeObject<dynamic>(foo);
|
||||
|
||||
if (results["transferring"] != null)
|
||||
@@ -3308,24 +3309,45 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
totalSize /= 1000000;
|
||||
downloadedSize /= 1000000;
|
||||
|
||||
// Logger.Log("Files: " + transfersComplete.ToString() + "/" + fileCount.ToString() + " (" + Convert.ToInt32((downloadedSize / totalSize) * 100).ToString() + "% Complete)");
|
||||
// Logger.Log("Downloaded: " + downloadedSize.ToString() + " of " + totalSize.ToString());
|
||||
|
||||
progressBar.IsIndeterminate = false;
|
||||
progressBar.Value = Convert.ToInt32((downloadedSize / totalSize) * 100);
|
||||
|
||||
int percent = 0;
|
||||
if (totalSize > 0)
|
||||
{
|
||||
percent = Convert.ToInt32((downloadedSize / totalSize) * 100);
|
||||
}
|
||||
|
||||
// Clamp to 0-99 while download is in progress to prevent brief 100% flashes
|
||||
percent = Math.Max(0, Math.Min(99, percent));
|
||||
|
||||
// Only allow progress to increase
|
||||
if (percent >= highestValidPercent)
|
||||
{
|
||||
highestValidPercent = percent;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Progress went backwards? Keep showing the highest valid percent we've seen
|
||||
percent = highestValidPercent;
|
||||
}
|
||||
|
||||
progressBar.Value = percent;
|
||||
|
||||
TimeSpan time = TimeSpan.FromSeconds(globalEta);
|
||||
etaLabel.Text = etaLabel.Text = "ETA: " + time.ToString(@"hh\:mm\:ss") + " left";
|
||||
|
||||
speedLabel.Text = "DLS: " + transfersComplete.ToString() + "/" + fileCount.ToString() + " files - " + string.Format("{0:0.00}", downloadSpeed) + " MB/s";
|
||||
UpdateProgressStatus(
|
||||
"Downloading",
|
||||
(int)transfersComplete + 1,
|
||||
(int)fileCount,
|
||||
percent,
|
||||
time,
|
||||
downloadSpeed);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
await Task.Delay(100);
|
||||
|
||||
}
|
||||
|
||||
if (removedownloading)
|
||||
@@ -3399,18 +3421,42 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
|
||||
if (UsingPublicConfig && otherError == false && gameDownloadOutput.Output != "Download skipped.")
|
||||
{
|
||||
// ETA tracking for extraction
|
||||
DateTime extractStart = DateTime.UtcNow;
|
||||
string currentExtractFile = "";
|
||||
|
||||
Thread extractionThread = new Thread(() =>
|
||||
{
|
||||
Invoke(new Action(() =>
|
||||
{
|
||||
speedLabel.Text = "Extracting..."; etaLabel.Text = "Please wait...";
|
||||
speedLabel.Text = "Extracting...";
|
||||
progressBar.IsIndeterminate = false;
|
||||
progressBar.Value = 0;
|
||||
progressBar.OperationType = "Extracting";
|
||||
isInDownloadExtract = true;
|
||||
}));
|
||||
|
||||
// Set up extraction callbacks
|
||||
Zip.ExtractionProgressCallback = (percent, eta) =>
|
||||
{
|
||||
this.Invoke(() =>
|
||||
{
|
||||
progressBar.Value = percent;
|
||||
UpdateProgressStatus("Extracting", percent: percent, eta: eta);
|
||||
|
||||
progressBar.StatusText = !string.IsNullOrEmpty(currentExtractFile)
|
||||
? $"{currentExtractFile} · {percent}%"
|
||||
: $"{percent}%";
|
||||
});
|
||||
};
|
||||
|
||||
Zip.ExtractionStatusCallback = (fileName) =>
|
||||
{
|
||||
currentExtractFile = fileName ?? "";
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
progressBar.OperationType = "Extracting";
|
||||
changeTitle("Extracting " + gameName);
|
||||
Zip.ExtractFile($"{settings.DownloadDir}\\{gameNameHash}\\{gameNameHash}.7z.001", $"{settings.DownloadDir}", PublicConfigFile.Password);
|
||||
changeTitle("");
|
||||
@@ -3425,6 +3471,12 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
this.Invoke(() => _ = FlexibleMessageBox.Show(Program.form, $"7zip error: {ex.Message}"));
|
||||
output += new ProcessOutput("", "Extract Failed");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Clear callbacks
|
||||
Zip.ExtractionProgressCallback = null;
|
||||
Zip.ExtractionStatusCallback = null;
|
||||
}
|
||||
})
|
||||
{
|
||||
IsBackground = true
|
||||
@@ -3436,6 +3488,8 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
progressBar.StatusText = ""; // Clear status after extraction
|
||||
|
||||
if (Directory.Exists($"{settings.DownloadDir}\\{gameNameHash}"))
|
||||
{
|
||||
Directory.Delete($"{settings.DownloadDir}\\{gameNameHash}", true);
|
||||
@@ -3449,8 +3503,6 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
progressBar.Value = 0;
|
||||
progressBar.IsIndeterminate = false;
|
||||
changeTitle("Installing game APK " + gameName);
|
||||
etaLabel.Text = "ETA: Wait for install...";
|
||||
speedLabel.Text = "DLS: Finished";
|
||||
if (File.Exists(Path.Combine(settings.DownloadDir, gameName, "install.txt")))
|
||||
{
|
||||
isinstalltxt = true;
|
||||
@@ -3508,7 +3560,6 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
t.Start();
|
||||
|
||||
changeTitle($"Sideloading APK...");
|
||||
etaLabel.Text = "Installing APK...";
|
||||
progressBar.IsIndeterminate = false;
|
||||
progressBar.OperationType = "Installing";
|
||||
progressBar.Value = 0;
|
||||
@@ -3516,7 +3567,7 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
// Use async method with progress
|
||||
output += await ADB.SideloadWithProgressAsync(
|
||||
apkFile,
|
||||
progress => this.Invoke(() => {
|
||||
(progress, eta) => this.Invoke(() => {
|
||||
if (progress == 0)
|
||||
{
|
||||
progressBar.IsIndeterminate = true;
|
||||
@@ -3527,16 +3578,23 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
progressBar.IsIndeterminate = false;
|
||||
progressBar.Value = progress;
|
||||
}
|
||||
UpdateProgressStatus("Installing APK", percent: progress, eta: eta);
|
||||
progressBar.StatusText = $"Installing · {progress}%";
|
||||
}),
|
||||
status => this.Invoke(() => {
|
||||
progressBar.StatusText = status;
|
||||
etaLabel.Text = status;
|
||||
if (!string.IsNullOrEmpty(status))
|
||||
{
|
||||
// "Completing Installation..."
|
||||
speedLabel.Text = status;
|
||||
progressBar.StatusText = status;
|
||||
}
|
||||
}),
|
||||
packagename,
|
||||
Sideloader.gameNameToSimpleName(gameName));
|
||||
|
||||
t.Stop();
|
||||
progressBar.IsIndeterminate = false;
|
||||
progressBar.StatusText = ""; // Clear status after APK install
|
||||
|
||||
Debug.WriteLine(wrDelimiter);
|
||||
if (Directory.Exists($"{settings.DownloadDir}\\{gameName}\\{packagename}"))
|
||||
@@ -3544,7 +3602,6 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
deleteOBB(packagename);
|
||||
|
||||
changeTitle($"Copying {packagename} OBB to device...");
|
||||
etaLabel.Text = "Copying OBB...";
|
||||
progressBar.Value = 0;
|
||||
progressBar.OperationType = "Copying OBB";
|
||||
|
||||
@@ -3553,41 +3610,27 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
|
||||
output += await ADB.CopyOBBWithProgressAsync(
|
||||
$"{settings.DownloadDir}\\{gameName}\\{packagename}",
|
||||
progress => this.Invoke(() =>
|
||||
(progress, eta) => this.Invoke(() =>
|
||||
{
|
||||
progressBar.Value = progress;
|
||||
speedLabel.Text = $"OBB: {progress}%";
|
||||
UpdateProgressStatus("Copying OBB", percent: progress, eta: eta);
|
||||
|
||||
if (!string.IsNullOrEmpty(currentObbStatusBase))
|
||||
{
|
||||
if (currentObbStatusBase.StartsWith("Preparing:", StringComparison.OrdinalIgnoreCase) ||
|
||||
currentObbStatusBase.StartsWith("Copying:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
progressBar.StatusText = currentObbStatusBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
// "filename · 73%"
|
||||
progressBar.StatusText = $"{currentObbStatusBase} · {progress}%";
|
||||
}
|
||||
progressBar.StatusText = $"{currentObbStatusBase} · {progress}%";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: just show the numeric percent in the bar
|
||||
progressBar.StatusText = $"{progress}%";
|
||||
}
|
||||
}),
|
||||
status => this.Invoke(() =>
|
||||
{
|
||||
currentObbStatusBase = status ?? string.Empty;
|
||||
if (currentObbStatusBase.StartsWith("Preparing:", StringComparison.OrdinalIgnoreCase) ||
|
||||
currentObbStatusBase.StartsWith("Copying:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
progressBar.StatusText = currentObbStatusBase;
|
||||
}
|
||||
}),
|
||||
Sideloader.gameNameToSimpleName(gameName));
|
||||
|
||||
progressBar.StatusText = ""; // Clear status after OBB copy
|
||||
changeTitle("");
|
||||
|
||||
if (!nodeviceonstart | DeviceConnected)
|
||||
@@ -3646,8 +3689,6 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
ShowPrcOutput(output);
|
||||
}
|
||||
progressBar.IsIndeterminate = false;
|
||||
etaLabel.Text = "ETA: Finished Queue";
|
||||
speedLabel.Text = "DLS: Finished Queue";
|
||||
gamesAreDownloading = false;
|
||||
isinstalling = false;
|
||||
|
||||
@@ -3768,8 +3809,6 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
ShowPrcOutput(output);
|
||||
}
|
||||
progressBar.IsIndeterminate = false;
|
||||
etaLabel.Text = "ETA: Finished Queue";
|
||||
speedLabel.Text = "DLS: Finished Queue";
|
||||
gamesAreDownloading = false;
|
||||
isinstalling = false;
|
||||
|
||||
@@ -7149,6 +7188,65 @@ function onYouTubeIframeAPIReady() {
|
||||
sideloadingStatusLabel.ForeColor = Color.FromArgb(93, 203, 173); // Accent green for enabled
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateProgressStatus(string operation,
|
||||
int current = 0,
|
||||
int total = 0,
|
||||
int percent = 0,
|
||||
TimeSpan? eta = null,
|
||||
double? speedMBps = null)
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(() => UpdateProgressStatus(operation, current, total, percent, eta, speedMBps));
|
||||
return;
|
||||
}
|
||||
|
||||
// Sync the progress bar's operation type to the current operation
|
||||
progressBar.OperationType = operation;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
// Operation name
|
||||
sb.Append(operation);
|
||||
|
||||
// Percentage
|
||||
if (percent > 0)
|
||||
{
|
||||
sb.Append($" ({percent}%)");
|
||||
}
|
||||
|
||||
// Speed
|
||||
if (speedMBps.HasValue && speedMBps.Value > 0)
|
||||
{
|
||||
sb.Append($" @ {speedMBps.Value:F1} MB/s");
|
||||
}
|
||||
|
||||
// File count if applicable
|
||||
if (total > 1)
|
||||
{
|
||||
sb.Append($" ({current}/{total})");
|
||||
}
|
||||
|
||||
// ETA
|
||||
if (eta.HasValue && eta.Value.TotalSeconds > 0)
|
||||
{
|
||||
sb.Append($" • ETA: {eta.Value:hh\\:mm\\:ss}");
|
||||
}
|
||||
|
||||
speedLabel.Text = sb.ToString();
|
||||
}
|
||||
|
||||
public void ClearProgressStatus()
|
||||
{
|
||||
if (this.InvokeRequired)
|
||||
{
|
||||
this.Invoke(ClearProgressStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
speedLabel.Text = "";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ControlExtensions
|
||||
|
||||
Reference in New Issue
Block a user