From 4dc11191f07976a14a1bf3e423f47e0bd3f8c87a Mon Sep 17 00:00:00 2001 From: jp64k <122999544+jp64k@users.noreply.github.com> Date: Wed, 4 Feb 2026 03:47:28 +0100 Subject: [PATCH] Implemented async real-time progress updates for drag and drop. Removed deprecated Sideload(...) and CopyOBB(...) functions Replaced the old sideload/OBB operations with our newer async, progress-aware flows to enable real-time progress feedback in the UI for non-blocking drag and drop operations. Also cleaned up a bit code and made minor logging adjustments. Updated "No Trailer found" message to disappear after 5 seconds --- ADB.cs | 72 -------- MainForm.cs | 498 ++++++++++++++++++++++++++++++++++++-------------- Sideloader.cs | 41 +++-- 3 files changed, 389 insertions(+), 222 deletions(-) diff --git a/ADB.cs b/ADB.cs index 9a3f752..3352889 100644 --- a/ADB.cs +++ b/ADB.cs @@ -680,78 +680,6 @@ namespace AndroidSideloader return $"Total space: {string.Format("{0:0.00}", (double)totalSize / 1000)}GB\nUsed space: {string.Format("{0:0.00}", (double)usedSize / 1000)}GB\nFree space: {string.Format("{0:0.00}", (double)freeSize / 1000)}GB"; } - - public static ProcessOutput Sideload(string path, string packagename = "") - { - ProcessOutput ret = new ProcessOutput(); - ret += RunAdbCommandToString($"install -g \"{path}\""); - string out2 = ret.Output + ret.Error; - - if (out2.Contains("failed")) - { - _ = Logger.Log(out2); - - if (out2.Contains("offline") && !settings.NodeviceMode) - { - DialogResult dialogResult2 = FlexibleMessageBox.Show(Program.form, "Device is offline. Press Yes to reconnect, or if you don't wish to connect and just want to download the game (requires unchecking \"Delete games after install\" from settings menu) then press No.", "Device offline.", MessageBoxButtons.YesNoCancel); - } - - if (out2.Contains($"signatures do not match previously") || out2.Contains("INSTALL_FAILED_VERSION_DOWNGRADE") || out2.Contains("signatures do not match") || out2.Contains("failed to install")) - { - ret.Error = string.Empty; - ret.Output = string.Empty; - - bool cancelClicked = false; - - if (!settings.AutoReinstall) - { - Program.form.Invoke((MethodInvoker)(() => - { - DialogResult dialogResult1 = FlexibleMessageBox.Show(Program.form, "In place upgrade has failed. Rookie can attempt to backup your save data and reinstall the game automatically, however some games do not store their saves in an accessible location (less than 5%). Continue with reinstall?", "In place upgrade failed.", MessageBoxButtons.OKCancel); - if (dialogResult1 == DialogResult.Cancel) - cancelClicked = true; - })); - } - - if (cancelClicked) - return ret; - - Program.form.changeTitle("Performing reinstall, please wait..."); - _ = RunAdbCommandToString("kill-server"); - _ = RunAdbCommandToString("devices"); - _ = RunAdbCommandToString($"pull \"/sdcard/Android/data/{MainForm.CurrPCKG}\" \"{Environment.CurrentDirectory}\""); - Program.form.changeTitle("Uninstalling game..."); - _ = Sideloader.UninstallGame(MainForm.CurrPCKG); - Program.form.changeTitle("Reinstalling game..."); - ret += RunAdbCommandToString($"install -g \"{path}\""); - _ = RunAdbCommandToString($"push \"{Environment.CurrentDirectory}\\{MainForm.CurrPCKG}\" /sdcard/Android/data/"); - - string directoryToDelete = Path.Combine(Environment.CurrentDirectory, MainForm.CurrPCKG); - if (Directory.Exists(directoryToDelete)) - { - if (directoryToDelete != Environment.CurrentDirectory) - { - FileSystemUtilities.TryDeleteDirectory(directoryToDelete); - } - } - - Program.form.changeTitle(""); - return ret; - } - } - - Program.form.changeTitle(""); - return ret; - } - - public static ProcessOutput CopyOBB(string path) - { - string folder = Path.GetFileName(path); - string lastFolder = Path.GetFileName(path); - return folder.Contains(".") - ? RunAdbCommandToString($"shell rm -rf \"/sdcard/Android/obb/{lastFolder}\" && mkdir \"/sdcard/Android/obb/{lastFolder}\"") + RunAdbCommandToString($"push \"{path}\" \"/sdcard/Android/obb\"") - : new ProcessOutput("No OBB Folder found"); - } } internal class EtaEstimator diff --git a/MainForm.cs b/MainForm.cs index f1c3c65..45394f2 100755 --- a/MainForm.cs +++ b/MainForm.cs @@ -872,22 +872,52 @@ namespace AndroidSideloader } ADB.DeviceID = GetDeviceID(); - Thread t1 = new Thread(() => - { - output += ADB.Sideload(path); - }) - { - IsBackground = true - }; - t1.Start(); + string filename = Path.GetFileName(path); + changeTitle($"Installing {filename}..."); + progressBar.IsIndeterminate = false; + progressBar.OperationType = "Installing"; + progressBar.Value = 0; + progressBar.StatusText = "Preparing..."; - while (t1.IsAlive) - { - await Task.Delay(100); - } + output = await ADB.SideloadWithProgressAsync( + path, + (percent, eta) => this.Invoke(() => + { + if (percent == 0) + { + progressBar.IsIndeterminate = true; + progressBar.OperationType = "Installing"; + } + else + { + progressBar.IsIndeterminate = false; + progressBar.Value = percent; + } + UpdateProgressStatus("Installing", percent: (int)Math.Round(percent), eta: eta); + progressBar.StatusText = $"Installing · {percent:0.0}%"; + }), + status => this.Invoke(() => + { + if (!string.IsNullOrEmpty(status)) + { + if (status.Contains("Completing Installation")) + { + speedLabel.Text = status; + } + progressBar.StatusText = status; + } + }), + "", + filename); + + // Reset UI on completion + progressBar.Value = 0; + progressBar.StatusText = ""; + progressBar.IsIndeterminate = false; + speedLabel.Text = ""; + changeTitle(""); showAvailableSpace(); - ShowPrcOutput(output); } @@ -980,31 +1010,45 @@ namespace AndroidSideloader progressBar.IsIndeterminate = false; progressBar.Value = 0; progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; + + string currentStatusBase = string.Empty; output = await ADB.CopyOBBWithProgressAsync( path, - (progress, eta) => this.Invoke(() => + (percent, eta) => this.Invoke(() => { - progressBar.Value = progress; - string etaStr = eta.HasValue && eta.Value.TotalSeconds > 0 - ? $" · ETA: {eta.Value:mm\\:ss}" - : ""; - speedLabel.Text = $"Progress: {progress}%{etaStr}"; + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + + if (!string.IsNullOrEmpty(currentStatusBase)) + { + progressBar.StatusText = $"{currentStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } }), status => this.Invoke(() => { - progressBar.StatusText = status; + currentStatusBase = status ?? string.Empty; + if (!string.IsNullOrEmpty(status)) + { + progressBar.StatusText = status; + } }), folderName); - progressBar.Value = 100; + // Reset UI on completion + progressBar.Value = 0; progressBar.StatusText = ""; - changeTitle("Done."); - showAvailableSpace(); - - ShowPrcOutput(output); - changeTitle(""); + progressBar.IsIndeterminate = false; speedLabel.Text = ""; + changeTitle(""); + + showAvailableSpace(); + ShowPrcOutput(output); } } @@ -1717,23 +1761,49 @@ namespace AndroidSideloader }; if (dialog.Show(Handle)) { - Thread t1 = new Thread(() => - { - Sideloader.RecursiveOutput = new ProcessOutput(String.Empty, String.Empty); - Sideloader.RecursiveCopyOBB(dialog.FileName); - }) - { - IsBackground = true - }; - t1.Start(); + changeTitle("Copying OBB folders to device..."); + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; + + Sideloader.RecursiveOutput = new ProcessOutput(String.Empty, String.Empty); + + string currentStatusBase = string.Empty; + + await Sideloader.RecursiveCopyOBBAsync( + dialog.FileName, + (percent, eta) => this.Invoke(() => + { + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + + if (!string.IsNullOrEmpty(currentStatusBase)) + { + progressBar.StatusText = $"{currentStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } + }), + status => this.Invoke(() => + { + currentStatusBase = status ?? string.Empty; + if (!string.IsNullOrEmpty(status)) + { + changeTitle($"Copying: {status}"); + } + })); + + // Reset UI on completion + progressBar.Value = 0; + progressBar.StatusText = ""; + progressBar.IsIndeterminate = false; + speedLabel.Text = ""; + changeTitle(""); showAvailableSpace(); - - while (t1.IsAlive) - { - await Task.Delay(100); - } - ShowPrcOutput(Sideloader.RecursiveOutput); } } @@ -1778,23 +1848,45 @@ namespace AndroidSideloader if (!data.Contains("+") && !data.Contains("_") && data.Contains(".")) { _ = Logger.Log($"Copying {data} to device"); - changeTitle($"Copying {data} to device..."); + string folderName = Path.GetFileName(data); + changeTitle($"Copying {folderName} to device..."); - Thread t2 = new Thread(() => + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; - { - output += ADB.CopyOBB(data); - }) - { - IsBackground = true - }; - t2.Start(); + string currentStatusBase = string.Empty; - while (t2.IsAlive) - { - await Task.Delay(100); - } + output += await ADB.CopyOBBWithProgressAsync( + data, + (percent, eta) => this.Invoke(() => + { + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + if (!string.IsNullOrEmpty(currentStatusBase)) + { + progressBar.StatusText = $"{currentStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } + }), + status => this.Invoke(() => + { + currentStatusBase = status ?? string.Empty; + if (!string.IsNullOrEmpty(status)) + { + changeTitle($"Copying: {status}"); + } + }), + folderName); + + // Reset UI after this operation + progressBar.StatusText = ""; + speedLabel.Text = ""; changeTitle(""); settings.CurrPckg = dir; settings.Save(); @@ -1829,42 +1921,88 @@ namespace AndroidSideloader }; t3.Tick += timer_Tick4; t3.Start(); - changeTitle($"Sideloading APK ({filename})"); - Thread t2 = new Thread(() => - { - output += ADB.Sideload(file2); - }) - { - IsBackground = true - }; - t2.Start(); - while (t2.IsAlive) - { - await Task.Delay(100); - } + changeTitle($"Sideloading APK ({filename})"); + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Installing"; + progressBar.StatusText = "Preparing..."; + + output += await ADB.SideloadWithProgressAsync( + file2, + (percent, eta) => this.Invoke(() => + { + if (percent == 0) + { + progressBar.IsIndeterminate = true; + progressBar.OperationType = "Installing"; + } + else + { + progressBar.IsIndeterminate = false; + progressBar.Value = percent; + } + UpdateProgressStatus("Installing", percent: (int)Math.Round(percent), eta: eta); + progressBar.StatusText = $"Installing · {percent:0.0}%"; + }), + status => this.Invoke(() => + { + if (!string.IsNullOrEmpty(status)) + { + if (status.Contains("Completing Installation")) + { + speedLabel.Text = status; + } + progressBar.StatusText = status; + } + }), + cmdout, + filename); t3.Stop(); + + // Reset after APK install + progressBar.StatusText = ""; + speedLabel.Text = ""; + if (Directory.Exists($"{pathname}\\{cmdout}")) { _ = Logger.Log($"Copying OBB folder to device- {cmdout}"); changeTitle($"Copying OBB folder to device..."); - Thread t1 = new Thread(() => - { - if (!string.IsNullOrEmpty(cmdout)) + + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; + + string obbStatusBase = string.Empty; + + output += await ADB.CopyOBBWithProgressAsync( + $"{pathname}\\{cmdout}", + (percent, eta) => this.Invoke(() => { - _ = ADB.RunAdbCommandToString($"shell rm -rf \"/sdcard/Android/obb/{cmdout}\" && mkdir \"/sdcard/Android/obb/{cmdout}\""); - } - _ = ADB.RunAdbCommandToString($"push \"{pathname}\\{cmdout}\" /sdcard/Android/obb/"); - }) - { - IsBackground = true - }; - t1.Start(); - while (t1.IsAlive) - { - await Task.Delay(100); - } + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + + if (!string.IsNullOrEmpty(obbStatusBase)) + { + progressBar.StatusText = $"{obbStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } + }), + status => this.Invoke(() => + { + obbStatusBase = status ?? string.Empty; + }), + cmdout); + + // Reset after OBB copy + progressBar.StatusText = ""; + speedLabel.Text = ""; + changeTitle(""); } } @@ -1900,24 +2038,46 @@ namespace AndroidSideloader string[] folders = Directory.GetDirectories(data); foreach (string folder in folders) { + string folderName = Path.GetFileName(folder); _ = Logger.Log($"Copying {folder} to device"); - changeTitle($"Copying {folder} to device..."); + changeTitle($"Copying {folderName} to device..."); - Thread t2 = new Thread(() => + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; - { - output += ADB.CopyOBB(folder); - }) - { - IsBackground = true - }; - t2.Start(); + string folderStatusBase = string.Empty; - while (t2.IsAlive) - { - await Task.Delay(100); - } + output += await ADB.CopyOBBWithProgressAsync( + folder, + (percent, eta) => this.Invoke(() => + { + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + if (!string.IsNullOrEmpty(folderStatusBase)) + { + progressBar.StatusText = $"{folderStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } + }), + status => this.Invoke(() => + { + folderStatusBase = status ?? string.Empty; + if (!string.IsNullOrEmpty(status)) + { + changeTitle($"Copying: {status}"); + } + }), + folderName); + + // Reset after folder copy + progressBar.StatusText = ""; + speedLabel.Text = ""; changeTitle(""); settings.CurrPckg = dir; settings.Save(); @@ -1981,43 +2141,85 @@ namespace AndroidSideloader timer.Start(); changeTitle($"Installing {dataname}..."); + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Installing"; + progressBar.StatusText = "Preparing..."; - Thread t1 = new Thread(() => - { - output += ADB.Sideload(data); - }) - { - IsBackground = true - }; - t1.Start(); - while (t1.IsAlive) - { - await Task.Delay(100); - } + output += await ADB.SideloadWithProgressAsync( + data, + (percent, eta) => this.Invoke(() => + { + if (percent == 0) + { + progressBar.IsIndeterminate = true; + progressBar.OperationType = "Installing"; + } + else + { + progressBar.IsIndeterminate = false; + progressBar.Value = percent; + } + UpdateProgressStatus("Installing", percent: (int)Math.Round(percent), eta: eta); + progressBar.StatusText = $"Installing · {percent:0.0}%"; + }), + status => this.Invoke(() => + { + if (!string.IsNullOrEmpty(status)) + { + if (status.Contains("Completing Installation")) + { + speedLabel.Text = status; + } + progressBar.StatusText = status; + } + }), + cmdout, + dataname); timer.Stop(); + // Reset after APK install + progressBar.StatusText = ""; + speedLabel.Text = ""; + if (Directory.Exists($"{pathname}\\{cmdout}")) { _ = Logger.Log($"Copying OBB folder to device- {cmdout}"); changeTitle($"Copying OBB folder to device..."); - Thread t2 = new Thread(() => - { - if (!string.IsNullOrEmpty(cmdout)) - { - _ = ADB.RunAdbCommandToString($"shell rm -rf \"/sdcard/Android/obb/{cmdout}\" && mkdir \"/sdcard/Android/obb/{cmdout}\""); - } - _ = ADB.RunAdbCommandToString($"push \"{pathname}\\{cmdout}\" /sdcard/Android/obb/"); - }) - { - IsBackground = true - }; - t2.Start(); - while (t2.IsAlive) - { - await Task.Delay(100); - } + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; + + string obbStatusBase = string.Empty; + + output += await ADB.CopyOBBWithProgressAsync( + $"{pathname}\\{cmdout}", + (percent, eta) => this.Invoke(() => + { + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + + if (!string.IsNullOrEmpty(obbStatusBase)) + { + progressBar.StatusText = $"{obbStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } + }), + status => this.Invoke(() => + { + obbStatusBase = status ?? string.Empty; + }), + cmdout); + + // Reset after OBB copy + progressBar.StatusText = ""; + speedLabel.Text = ""; changeTitle(""); } } @@ -2034,21 +2236,41 @@ namespace AndroidSideloader File.Copy(data, Path.Combine(foldername, filename)); path = foldername; - Thread t1 = new Thread(() => - { - output += ADB.CopyOBB(path); - }) - { - IsBackground = true - }; _ = Logger.Log($"Copying OBB folder to device- {path}"); changeTitle($"Copying OBB folder to device ({filename})"); - t1.Start(); - while (t1.IsAlive) - { - await Task.Delay(100); - } + progressBar.IsIndeterminate = false; + progressBar.Value = 0; + progressBar.OperationType = "Copying OBB"; + progressBar.StatusText = "Preparing..."; + + string obbStatusBase = string.Empty; + + output += await ADB.CopyOBBWithProgressAsync( + path, + (percent, eta) => this.Invoke(() => + { + progressBar.Value = percent; + UpdateProgressStatus("Copying OBB", percent: (int)Math.Round(percent), eta: eta); + + if (!string.IsNullOrEmpty(obbStatusBase)) + { + progressBar.StatusText = $"{obbStatusBase} · {percent:0.0}%"; + } + else + { + progressBar.StatusText = $"Copying · {percent:0.0}%"; + } + }), + status => this.Invoke(() => + { + obbStatusBase = status ?? string.Empty; + }), + filename); + + // Reset after OBB copy + progressBar.StatusText = ""; + speedLabel.Text = ""; FileSystemUtilities.TryDeleteDirectory(foldername); changeTitle(""); @@ -2106,7 +2328,11 @@ namespace AndroidSideloader } } + // Final reset of all UI elements + progressBar.Value = 0; + progressBar.StatusText = ""; progressBar.IsIndeterminate = false; + speedLabel.Text = ""; showAvailableSpace(); ShowPrcOutput(output); @@ -6000,7 +6226,7 @@ function onYouTubeIframeAPIReady() { var videoId = await ResolveVideoIdAsync(CurrentGameName); if (string.IsNullOrEmpty(videoId)) { - changeTitle("No Trailer found"); + changeTitle("No Trailer found", true); ShowVideoPlaceholder(); } else diff --git a/Sideloader.cs b/Sideloader.cs index 5c5f0c1..09538c2 100644 --- a/Sideloader.cs +++ b/Sideloader.cs @@ -1,13 +1,14 @@ -using JR.Utils.GUI.Forms; +using AndroidSideloader.Utilities; +using JR.Utils.GUI.Forms; using System; using System.Diagnostics; +using System.Drawing; using System.IO; using System.Management; using System.Net; using System.Text.RegularExpressions; -using System.Drawing; +using System.Threading.Tasks; using System.Windows.Forms; -using AndroidSideloader.Utilities; namespace AndroidSideloader { @@ -84,9 +85,12 @@ namespace AndroidSideloader return output; } - //Recursive sideload any apk fileD + //Recursive sideload any apk file public static ProcessOutput RecursiveOutput = new ProcessOutput(); - public static void RecursiveSideload(string FolderPath) + public static async Task RecursiveSideloadAsync( + string FolderPath, + Action progressCallback = null, + Action statusCallback = null) { try { @@ -94,31 +98,40 @@ namespace AndroidSideloader { if (Path.GetExtension(f) == ".apk") { - RecursiveOutput += ADB.Sideload(f); + string gameName = Path.GetFileNameWithoutExtension(f); + statusCallback?.Invoke(gameName); + RecursiveOutput += await ADB.SideloadWithProgressAsync(f, progressCallback, statusCallback, "", gameName); } } foreach (string d in Directory.GetDirectories(FolderPath)) { - RecursiveSideload(d); + await RecursiveSideloadAsync(d, progressCallback, statusCallback); } } catch (Exception ex) { _ = Logger.Log(ex.Message, LogLevel.ERROR); } } //Recursive copy any obb folder - public static void RecursiveCopyOBB(string FolderPath) + public static async Task RecursiveCopyOBBAsync( + string FolderPath, + Action progressCallback = null, + Action statusCallback = null) { try { - foreach (string f in Directory.GetFiles(FolderPath)) - { - RecursiveOutput += ADB.CopyOBB(f); - } - foreach (string d in Directory.GetDirectories(FolderPath)) { - RecursiveCopyOBB(d); + string folderName = Path.GetFileName(d); + if (folderName.Contains(".")) + { + statusCallback?.Invoke(folderName); + RecursiveOutput += await ADB.CopyOBBWithProgressAsync(d, progressCallback, statusCallback, folderName); + } + else + { + await RecursiveCopyOBBAsync(d, progressCallback, statusCallback); + } } } catch (Exception ex) { _ = Logger.Log(ex.Message, LogLevel.ERROR); }