Compare commits

..

1 Commits

Author SHA1 Message Date
nerdunit
963c75b35e Create version 2021-04-13 22:05:54 +08:00
95 changed files with 6528 additions and 29427 deletions

8
.gitignore vendored
View File

@@ -1,8 +0,0 @@
*.pdb
*.xml
*.xsd
AndroidSideloader.csproj.user
.vs/
bin/
packages/

BIN
7z.dll

Binary file not shown.

BIN
7z.exe

Binary file not shown.

BIN
7z64.dll

Binary file not shown.

BIN
7z64.exe

Binary file not shown.

821
ADB.cs
View File

@@ -1,782 +1,125 @@
using AdvancedSharpAdbClient;
using AdvancedSharpAdbClient.DeviceCommands;
using AdvancedSharpAdbClient.Models;
using AdvancedSharpAdbClient.Receivers;
using AndroidSideloader.Utilities;
using JR.Utils.GUI.Forms;
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
namespace AndroidSideloader
{
internal class ADB
class ADB
{
private static readonly SettingsManager settings = SettingsManager.Instance;
public static string adbFolderPath = Path.Combine(Environment.CurrentDirectory, "platform-tools");
public static string adbFilePath = Path.Combine(adbFolderPath, "adb.exe");
static Process adb = new Process();
public static string adbFolderPath = Environment.CurrentDirectory + "\\adb";
public static string adbFilePath = adbFolderPath + "\\adb.exe";
public static string DeviceID = "";
public static string package = "";
public static bool wirelessadbON;
// AdbClient for direct protocol communication
private static AdbClient _adbClient;
private static DeviceData _currentDevice;
// Gets or initializes the AdbClient instance
private static AdbClient GetAdbClient()
public static ProcessOutput RunAdbCommandToString(string command)
{
if (_adbClient == null)
{
// Ensure ADB server is started
if (!AdbServer.Instance.GetStatus().IsRunning)
{
var server = new AdbServer();
var result = server.StartServer(adbFilePath, false);
Logger.Log($"ADB server start result: {result}");
}
_adbClient = new AdbClient();
}
return _adbClient;
}
// Gets the current device for AdbClient operations
private static DeviceData GetCurrentDevice()
{
var client = GetAdbClient();
var devices = client.GetDevices();
if (devices == null || !devices.Any())
{
Logger.Log("No devices found via AdbClient", LogLevel.WARNING);
return default;
}
// If DeviceID is set, find that specific device
if (!string.IsNullOrEmpty(DeviceID) && DeviceID.Length > 1)
{
var device = devices.FirstOrDefault(d => d.Serial == DeviceID || d.Serial.StartsWith(DeviceID));
if (device.Serial != null)
{
_currentDevice = device;
return device;
}
}
// Otherwise return the first available device
_currentDevice = devices.First();
return _currentDevice;
}
public static ProcessOutput RunAdbCommandToString(string command, bool suppressLogging = false)
{
command = command.Replace("adb", "");
settings.ADBFolder = adbFolderPath;
settings.ADBPath = adbFilePath;
settings.Save();
if (DeviceID.Length > 1)
{
command = $" -s {DeviceID} {command}";
}
if (!suppressLogging && !command.Contains("dumpsys") && !command.Contains("shell pm list packages") && !command.Contains("KEYCODE_WAKEUP"))
{
string logcmd = command;
if (logcmd.Contains(Environment.CurrentDirectory))
{
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
}
_ = Logger.Log($"Running command: {logcmd}");
}
Logger.Log($"Running command {command}");
adb.StartInfo.FileName = adbFilePath;
adb.StartInfo.Arguments = command;
adb.StartInfo.RedirectStandardError = true;
adb.StartInfo.RedirectStandardInput = true;
adb.StartInfo.RedirectStandardOutput = true;
adb.StartInfo.CreateNoWindow = true;
adb.StartInfo.UseShellExecute = false;
adb.StartInfo.WorkingDirectory = adbFolderPath;
bool isConnectCommand = command.Contains("connect");
int timeoutMs = isConnectCommand ? 5000 : -1; // 5 second timeout for connect commands
adb.Start();
adb.StandardInput.WriteLine(command);
adb.StandardInput.Flush();
adb.StandardInput.Close();
using (Process adb = new Process())
{
adb.StartInfo.FileName = adbFilePath;
adb.StartInfo.Arguments = command;
adb.StartInfo.RedirectStandardError = true;
adb.StartInfo.RedirectStandardOutput = true;
adb.StartInfo.CreateNoWindow = true;
adb.StartInfo.UseShellExecute = false;
adb.StartInfo.WorkingDirectory = adbFolderPath;
_ = adb.Start();
string output = "";
string error = "";
try
{
if (isConnectCommand)
{
// For connect commands, we use async reading with timeout to avoid blocking on TCP timeout
var outputTask = adb.StandardOutput.ReadToEndAsync();
var errorTask = adb.StandardError.ReadToEndAsync();
bool exited = adb.WaitForExit(timeoutMs);
if (!exited)
{
try { adb.Kill(); } catch { }
adb.WaitForExit(1000);
output = "Connection timed out";
error = "cannot connect: Connection timed out";
Logger.Log($"ADB connect command timed out after {timeoutMs}ms", LogLevel.WARNING);
}
else
{
// Process exited within timeout, safe to read output
output = outputTask.Result;
error = errorTask.Result;
}
}
else
{
// For non-connect commands, read output normally
output = adb.StandardOutput.ReadToEnd();
error = adb.StandardError.ReadToEnd();
}
}
catch (Exception ex)
{
Logger.Log($"Error reading ADB output: {ex.Message}", LogLevel.WARNING);
}
if (error.Contains("ADB_VENDOR_KEYS") && !settings.AdbDebugWarned)
{
ADBDebugWarning();
}
if (error.Contains("not enough storage space"))
{
_ = FlexibleMessageBox.Show(Program.form, "There is not enough room on your device to install this package. Please clear AT LEAST 2x the amount of the app you are trying to install.");
}
if (!suppressLogging && !output.Contains("version") && !output.Contains("KEYCODE_WAKEUP") && !output.Contains("Filesystem") && !output.Contains("package:") && !output.Equals(null))
{
_ = Logger.Log(output);
}
_ = Logger.Log(error, LogLevel.ERROR);
return new ProcessOutput(output, error);
}
}
// Executes a shell command on the device.
private static void ExecuteShellCommand(AdbClient client, DeviceData device, string command)
{
var receiver = new ConsoleOutputReceiver();
client.ExecuteRemoteCommand(command, device, receiver);
}
// Copies and installs an APK with real-time progress reporting using AdvancedSharpAdbClient
public static async Task<ProcessOutput> SideloadWithProgressAsync(
string path,
Action<float, TimeSpan?> progressCallback = null,
Action<string> statusCallback = null,
string packagename = "",
string gameName = "")
{
statusCallback?.Invoke("Installing APK...");
progressCallback?.Invoke(0, null);
string output = "";
string error = "";
try
{
var device = GetCurrentDevice();
if (device.Serial == null)
{
return new ProcessOutput("", "No device connected");
}
var client = GetAdbClient();
var packageManager = new PackageManager(client, device);
statusCallback?.Invoke("Installing APK...");
// Throttle UI updates to prevent lag
DateTime lastProgressUpdate = DateTime.MinValue;
float lastReportedPercent = -1;
const int ThrottleMs = 100; // Update UI every 100ms
// Shared ETA engine (percent-units)
var eta = new EtaEstimator(alpha: 0.05, reanchorThreshold: 0.20);
// Create install progress handler
Action<InstallProgressEventArgs> installProgress = (args) =>
{
float percent = 0;
string status = null;
TimeSpan? displayEta = null;
switch (args.State)
{
case PackageInstallProgressState.Preparing:
percent = 0;
status = "Preparing...";
eta.Reset();
break;
case PackageInstallProgressState.Uploading:
percent = (float)args.UploadProgress;
// Update ETA engine using percent as units (0..100)
if (percent > 0 && percent < 100)
{
eta.Update(totalUnits: 100, doneUnits: (long)Math.Round(percent));
displayEta = eta.GetDisplayEta();
}
else
{
displayEta = eta.GetDisplayEta();
}
status = $"Installing · {percent:0.0}%";
break;
case PackageInstallProgressState.Installing:
percent = 100;
status = "Completing Installation...";
displayEta = null;
break;
case PackageInstallProgressState.Finished:
percent = 100;
status = "";
displayEta = null;
break;
default:
percent = 100;
status = "";
displayEta = null;
break;
}
var updateNow = DateTime.UtcNow;
bool shouldUpdate = (updateNow - lastProgressUpdate).TotalMilliseconds >= ThrottleMs
|| Math.Abs(percent - lastReportedPercent) >= 0.1f
|| args.State != PackageInstallProgressState.Uploading;
if (shouldUpdate)
{
lastProgressUpdate = updateNow;
lastReportedPercent = percent;
// ETA goes back via progress callback (label); status remains percent-only string for inner bar
progressCallback?.Invoke(percent, displayEta);
if (status != null) statusCallback?.Invoke(status);
}
};
await Task.Run(() =>
{
packageManager.InstallPackage(path, installProgress);
});
progressCallback?.Invoke(100, null);
statusCallback?.Invoke("");
return new ProcessOutput($"{gameName}: Success\n");
output = adb.StandardOutput.ReadToEnd();
error = adb.StandardError.ReadToEnd();
}
catch (Exception ex)
{
Logger.Log($"SideloadWithProgressAsync error: {ex.Message}", LogLevel.ERROR);
catch { }
// Signature mismatches and version downgrades can be fixed by reinstalling
bool isReinstallEligible = ex.Message.Contains("signatures do not match") ||
ex.Message.Contains("INSTALL_FAILED_VERSION_DOWNGRADE") ||
ex.Message.Contains("failed to install");
// For insufficient storage, offer reinstall if it's an upgrade
// As uninstalling old version frees space for the new one
bool isStorageIssue = ex.Message.Contains("INSUFFICIENT_STORAGE");
bool isUpgrade = !string.IsNullOrEmpty(packagename) &&
settings.InstalledApps.Contains(packagename);
if (isStorageIssue && isUpgrade)
{
isReinstallEligible = true;
}
if (isReinstallEligible)
{
bool cancelClicked = false;
if (!settings.AutoReinstall)
{
string message = isStorageIssue
? "Installation failed due to insufficient storage. Since this is an upgrade, Rookie can uninstall the old version first to free up space, then install the new version.\n\nRookie will also 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 has failed. Rookie will 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?";
string title = isStorageIssue ? "Insufficient Storage" : "In place upgrade failed";
Program.form.Invoke(() =>
{
DialogResult dialogResult1 = FlexibleMessageBox.Show(Program.form,
message, title, MessageBoxButtons.OKCancel);
if (dialogResult1 == DialogResult.Cancel)
cancelClicked = true;
});
}
if (cancelClicked)
return new ProcessOutput("", "Installation cancelled by user");
statusCallback?.Invoke("Performing reinstall...");
try
{
var device = GetCurrentDevice();
var client = GetAdbClient();
var packageManager = new PackageManager(client, device);
statusCallback?.Invoke("Backing up save data...");
_ = RunAdbCommandToString($"pull \"/sdcard/Android/data/{packagename}\" \"{Environment.CurrentDirectory}\"");
statusCallback?.Invoke("Uninstalling old version...");
packageManager.UninstallPackage(packagename);
statusCallback?.Invoke("Reinstalling game...");
Action<InstallProgressEventArgs> reinstallProgress = (args) =>
{
if (args.State == PackageInstallProgressState.Uploading)
{
progressCallback?.Invoke((float)args.UploadProgress, null);
}
};
packageManager.InstallPackage(path, reinstallProgress);
statusCallback?.Invoke("Restoring save data...");
_ = RunAdbCommandToString($"push \"{Environment.CurrentDirectory}\\{packagename}\" /sdcard/Android/data/");
string directoryToDelete = Path.Combine(Environment.CurrentDirectory, packagename);
if (Directory.Exists(directoryToDelete) && directoryToDelete != Environment.CurrentDirectory)
{
FileSystemUtilities.TryDeleteDirectory(directoryToDelete);
}
progressCallback?.Invoke(100, null);
return new ProcessOutput($"{gameName}: Reinstall: Success\n", "");
}
catch (Exception reinstallEx)
{
return new ProcessOutput("", $"{gameName}: Reinstall Failed: {reinstallEx.Message}\n");
}
}
// Return the error message so it's displayed to the user
return new ProcessOutput("", $"\n{gameName}: {ex.Message}");
}
}
// Copies OBB folder with real-time progress reporting using AdvancedSharpAdbClient
public static async Task<ProcessOutput> CopyOBBWithProgressAsync(
string localPath,
Action<float, TimeSpan?> progressCallback = null,
Action<string> statusCallback = null,
string gameName = "")
{
string folderName = Path.GetFileName(localPath);
if (!folderName.Contains("."))
{
return new ProcessOutput("No OBB Folder found");
}
try
{
var device = GetCurrentDevice();
if (device.Serial == null)
{
return new ProcessOutput("", "No device connected");
}
var client = GetAdbClient();
string remotePath = $"/sdcard/Android/obb/{folderName}";
statusCallback?.Invoke($"Preparing: {folderName}");
progressCallback?.Invoke(0, null);
// Delete existing OBB folder and create new one
ExecuteShellCommand(client, device, $"rm -rf \"{remotePath}\"");
ExecuteShellCommand(client, device, $"mkdir -p \"{remotePath}\"");
// Get all files to push and calculate total size
var files = Directory.GetFiles(localPath, "*", SearchOption.AllDirectories);
long totalBytes = files.Sum(f => new FileInfo(f).Length);
long transferredBytes = 0;
// Throttle UI updates to prevent lag
DateTime lastProgressUpdate = DateTime.MinValue;
float lastReportedPercent = -1;
const int ThrottleMs = 100; // Update UI every 100ms
// Shared ETA engine (bytes-units)
var eta = new EtaEstimator(alpha: 0.10, reanchorThreshold: 0.20);
statusCallback?.Invoke($"Copying: {folderName}");
using (var syncService = new SyncService(client, device))
{
foreach (var file in files)
{
string relativePath = file.Substring(localPath.Length)
.TrimStart('\\', '/')
.Replace('\\', '/');
string remoteFilePath = $"{remotePath}/{relativePath}";
string fileName = Path.GetFileName(file);
// Ensure remote directory exists
string remoteDir = remoteFilePath.Substring(0, remoteFilePath.LastIndexOf('/'));
ExecuteShellCommand(client, device, $"mkdir -p \"{remoteDir}\"");
var fileInfo = new FileInfo(file);
long fileSize = fileInfo.Length;
long capturedTransferredBytes = transferredBytes;
Action<SyncProgressChangedEventArgs> progressHandler = (args) =>
{
long totalProgressBytes = capturedTransferredBytes + args.ReceivedBytesSize;
float overallPercent = totalBytes > 0
? (float)(totalProgressBytes * 100.0 / totalBytes)
: 0f;
overallPercent = Math.Max(0, Math.Min(100, overallPercent));
// Update ETA engine in bytes
if (totalBytes > 0 && totalProgressBytes > 0 && overallPercent < 100)
{
eta.Update(totalUnits: totalBytes, doneUnits: totalProgressBytes);
}
TimeSpan? displayEta = eta.GetDisplayEta();
var now2 = DateTime.UtcNow;
bool shouldUpdate = (now2 - lastProgressUpdate).TotalMilliseconds >= ThrottleMs
|| Math.Abs(overallPercent - lastReportedPercent) >= 0.1f;
if (shouldUpdate)
{
lastProgressUpdate = now2;
lastReportedPercent = overallPercent;
progressCallback?.Invoke(overallPercent, displayEta);
statusCallback?.Invoke(fileName);
}
};
using (var stream = File.OpenRead(file))
{
await Task.Run(() =>
{
syncService.Push(
stream,
remoteFilePath,
UnixFileStatus.DefaultFileMode,
DateTime.Now,
progressHandler,
false);
});
}
transferredBytes += fileSize;
}
}
progressCallback?.Invoke(100, null);
statusCallback?.Invoke("");
return new ProcessOutput($"{gameName}: OBB transfer: Success\n", "");
}
catch (Exception ex)
{
Logger.Log($"CopyOBBWithProgressAsync error: {ex.Message}", LogLevel.ERROR);
return new ProcessOutput("", $"{gameName}: OBB transfer: Failed: {ex.Message}\n");
}
}
public static ProcessOutput RunAdbCommandToStringWOADB(string result, string path)
{
string command = result;
string logcmd = command;
if (logcmd.Contains(Environment.CurrentDirectory))
{
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
}
_ = Logger.Log($"Running command: {logcmd}");
using (var adb = new Process())
{
adb.StartInfo.FileName = "cmd.exe";
adb.StartInfo.RedirectStandardError = true;
adb.StartInfo.RedirectStandardInput = true;
adb.StartInfo.RedirectStandardOutput = true;
adb.StartInfo.CreateNoWindow = true;
adb.StartInfo.UseShellExecute = false;
adb.StartInfo.WorkingDirectory = Path.GetDirectoryName(path);
_ = adb.Start();
adb.StandardInput.WriteLine(command);
adb.StandardInput.Flush();
adb.StandardInput.Close();
string output = "";
string error = "";
try
{
output += adb.StandardOutput.ReadToEnd();
error += adb.StandardError.ReadToEnd();
}
catch { }
if (command.Contains("connect"))
{
bool graceful = adb.WaitForExit(3000);
if (!graceful)
{
adb.Kill();
adb.WaitForExit();
}
}
if (error.Contains("ADB_VENDOR_KEYS") && settings.AdbDebugWarned)
{
ADBDebugWarning();
}
_ = Logger.Log(output);
_ = Logger.Log(error, LogLevel.ERROR);
return new ProcessOutput(output, error);
}
}
public static ProcessOutput RunCommandToString(string result, string path = "")
{
string command = result;
string logcmd = command;
if (logcmd.Contains(Environment.CurrentDirectory))
{
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
}
Logger.Log($"Running command: {logcmd}");
try
{
using (var proc = new Process())
{
proc.StartInfo.FileName = $@"{Path.GetPathRoot(Environment.SystemDirectory)}\Windows\System32\cmd.exe";
proc.StartInfo.Arguments = command;
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardInput = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.CreateNoWindow = true;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.WorkingDirectory = Path.GetDirectoryName(path);
proc.Start();
proc.StandardInput.WriteLine(command);
proc.StandardInput.Flush();
proc.StandardInput.Close();
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
if (command.Contains("connect"))
{
bool graceful = proc.WaitForExit(3000);
if (!graceful)
{
proc.Kill();
proc.WaitForExit();
}
}
else
{
proc.WaitForExit();
}
if (error.Contains("ADB_VENDOR_KEYS") && settings.AdbDebugWarned)
{
ADBDebugWarning();
}
Logger.Log(output);
Logger.Log(error, LogLevel.ERROR);
return new ProcessOutput(output, error);
}
}
catch (Exception ex)
{
Logger.Log($"Error in RunCommandToString: {ex.Message}", LogLevel.ERROR);
return new ProcessOutput("", $"Exception occurred: {ex.Message}");
}
}
public static void ADBDebugWarning()
{
Program.form.Invoke(() =>
{
DialogResult dialogResult = FlexibleMessageBox.Show(Program.form,
"On your headset, click on the Notifications Bell, and then select the USB Detected notification to enable Connections.",
"ADB Debugging not enabled.", MessageBoxButtons.OKCancel);
if (dialogResult == DialogResult.Cancel)
{
settings.Save();
}
});
adb.WaitForExit();
Logger.Log(output);
Logger.Log(error);
return new ProcessOutput(output, error);
}
public static ProcessOutput UninstallPackage(string package)
{
WakeDevice();
ProcessOutput output = new ProcessOutput("", "");
output += RunAdbCommandToString($"shell pm uninstall -k --user 0 {package}");
output += RunAdbCommandToString($"shell pm uninstall {package}");
// Prefix the output with the simple game name
string label = Sideloader.gameNameToSimpleName(Sideloader.PackageNametoGameName(package));
if (!string.IsNullOrEmpty(output.Output))
{
output.Output = $"{label}: {output.Output}";
}
if (!string.IsNullOrEmpty(output.Error))
{
output.Error = $"{label}: {output.Error}";
}
return output;
}
public static string GetAvailableSpace()
{
long totalSize = 0;
long usedSize = 0;
long freeSize = 0;
string[] output = RunAdbCommandToString("shell df").Output.Split('\n');
long usedSize = 0;
long freeSize = 0;
WakeDevice();
var output = RunAdbCommandToString("shell df").Output.Split('\n');
foreach (string currLine in output)
{
if (currLine.StartsWith("/dev/fuse") || currLine.StartsWith("/data/media"))
if (currLine.StartsWith("/data/media"))
{
string[] foo = currLine.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (foo.Length >= 4)
var foo = currLine.Split(' ');
int i = 0;
foreach (string curr in foo)
{
totalSize = long.Parse(foo[1]) / 1000;
usedSize = long.Parse(foo[2]) / 1000;
freeSize = long.Parse(foo[3]) / 1000;
break;
if (curr.Length > 1)
{
switch (i)
{
case 0:
break;
case 1:
totalSize = Int64.Parse(curr) / 1000;
break;
case 2:
usedSize = Int64.Parse(curr) / 1000;
break;
case 3:
freeSize = Int64.Parse(curr) / 1000;
break;
default:
break;
}
i++;
}
}
}
}
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";
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 void WakeDevice()
{
RunAdbCommandToString("shell input keyevent KEYCODE_WAKEUP");
}
public static ProcessOutput Sideload(string path)
{
WakeDevice();
return RunAdbCommandToString($"install -g -r \"{path}\"");
}
public static ProcessOutput CopyOBB(string path)
{
WakeDevice();
if (SideloaderUtilities.CheckFolderIsObb(path))
return RunAdbCommandToString($"push \"{path}\" /sdcard/Android/obb");
return new ProcessOutput("","");
}
}
internal class EtaEstimator
{
private readonly double _alpha; // EWMA smoothing
private readonly double _reanchorThreshold; // % difference required to re-anchor
private readonly double _minSampleSeconds; // ignore too-short dt
private DateTime _lastSampleTimeUtc;
private long _lastSampleDoneUnits;
private double _smoothedUnitsPerSecond;
private TimeSpan? _etaAnchorValue;
private DateTime _etaAnchorTimeUtc;
public EtaEstimator(double alpha, double reanchorThreshold, double minSampleSeconds = 0.15)
{
_alpha = alpha;
_reanchorThreshold = reanchorThreshold;
_minSampleSeconds = minSampleSeconds;
Reset();
}
public void Reset()
{
_lastSampleTimeUtc = DateTime.UtcNow;
_lastSampleDoneUnits = 0;
_smoothedUnitsPerSecond = 0;
_etaAnchorValue = null;
_etaAnchorTimeUtc = DateTime.UtcNow;
}
// Updates internal rate estimate and re-anchors ETA
// totalUnits: total work units (e.g., 100 for percent, or totalBytes for bytes)
// doneUnits: completed work units so far (e.g., percent, or bytes transferred)
public void Update(long totalUnits, long doneUnits)
{
var now = DateTime.UtcNow;
if (totalUnits <= 0) return;
doneUnits = Math.Max(0, Math.Min(totalUnits, doneUnits));
long remainingUnits = Math.Max(0, totalUnits - doneUnits);
double dt = (now - _lastSampleTimeUtc).TotalSeconds;
long dUnits = doneUnits - _lastSampleDoneUnits;
if (dt >= _minSampleSeconds && dUnits > 0)
{
double instUnitsPerSecond = dUnits / dt;
if (_smoothedUnitsPerSecond <= 0)
_smoothedUnitsPerSecond = instUnitsPerSecond;
else
_smoothedUnitsPerSecond = _alpha * instUnitsPerSecond + (1 - _alpha) * _smoothedUnitsPerSecond;
_lastSampleTimeUtc = now;
_lastSampleDoneUnits = doneUnits;
}
if (_smoothedUnitsPerSecond > 1e-6 && remainingUnits > 0)
{
var newEta = TimeSpan.FromSeconds(remainingUnits / _smoothedUnitsPerSecond);
if (newEta < TimeSpan.Zero) newEta = TimeSpan.Zero;
if (!_etaAnchorValue.HasValue)
{
_etaAnchorValue = newEta;
_etaAnchorTimeUtc = now;
}
else
{
// What countdown would currently show
var predictedNow = _etaAnchorValue.Value - (now - _etaAnchorTimeUtc);
if (predictedNow < TimeSpan.Zero) predictedNow = TimeSpan.Zero;
double baseSeconds = Math.Max(1, predictedNow.TotalSeconds);
double diffRatio = Math.Abs(newEta.TotalSeconds - predictedNow.TotalSeconds) / baseSeconds;
if (diffRatio > _reanchorThreshold)
{
_etaAnchorValue = newEta;
_etaAnchorTimeUtc = now;
}
}
}
}
// Returns a countdown ETA for UI display
public TimeSpan? GetDisplayEta()
{
if (!_etaAnchorValue.HasValue) return null;
var remaining = _etaAnchorValue.Value - (DateTime.UtcNow - _etaAnchorTimeUtc);
if (remaining < TimeSpan.Zero) remaining = TimeSpan.Zero;
return TimeSpan.FromSeconds(Math.Ceiling(remaining.TotalSeconds));
}
}
}
}

View File

@@ -1,244 +0,0 @@
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class AdbCommandForm : Form
{
public string Command { get; private set; }
public bool ToggleUpdatesClicked { get; private set; }
public AdbCommandForm()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
this.ShowIcon = true; // Enable icon
}
private void InitializeComponent()
{
this.lblTitle = new Label();
this.txtCommand = new TextBox();
this.btnSend = new RoundButton();
this.btnToggleUpdates = new RoundButton();
this.btnClose = new RoundButton();
this.separator = new Panel();
this.lblHint = new Label();
this.SuspendLayout();
//
// lblTitle
//
this.lblTitle.AutoSize = true;
this.lblTitle.Font = new Font("Segoe UI", 11F, FontStyle.Bold);
this.lblTitle.ForeColor = Color.FromArgb(93, 203, 173);
this.lblTitle.Location = new Point(20, 15);
this.lblTitle.Name = "lblTitle";
this.lblTitle.Size = new Size(140, 20);
this.lblTitle.TabIndex = 0;
this.lblTitle.Text = "Run ADB Command";
//
// txtCommand
//
this.txtCommand.BackColor = Color.FromArgb(40, 44, 52);
this.txtCommand.BorderStyle = BorderStyle.FixedSingle;
this.txtCommand.Font = new Font("Consolas", 10F);
this.txtCommand.ForeColor = Color.White;
this.txtCommand.Location = new Point(24, 50);
this.txtCommand.Name = "txtCommand";
this.txtCommand.Size = new Size(292, 23);
this.txtCommand.TabIndex = 1;
this.txtCommand.KeyPress += TxtCommand_KeyPress;
//
// lblHint
//
this.lblHint.AutoSize = true;
this.lblHint.Font = new Font("Segoe UI", 8F);
this.lblHint.ForeColor = Color.FromArgb(120, 120, 120);
this.lblHint.Location = new Point(24, 78);
this.lblHint.Name = "lblHint";
this.lblHint.Size = new Size(200, 13);
this.lblHint.TabIndex = 2;
this.lblHint.Text = "Enter command without \"adb\" prefix";
//
// separator
//
this.separator.BackColor = Color.FromArgb(50, 55, 65);
this.separator.Location = new Point(20, 105);
this.separator.Name = "separator";
this.separator.Size = new Size(300, 1);
this.separator.TabIndex = 3;
//
// btnSend
//
this.btnSend.Active1 = Color.FromArgb(113, 223, 193);
this.btnSend.Active2 = Color.FromArgb(113, 223, 193);
this.btnSend.BackColor = Color.Transparent;
this.btnSend.Cursor = Cursors.Hand;
this.btnSend.DialogResult = DialogResult.OK;
this.btnSend.Disabled1 = Color.FromArgb(32, 35, 45);
this.btnSend.Disabled2 = Color.FromArgb(25, 28, 35);
this.btnSend.DisabledStrokeColor = Color.FromArgb(50, 55, 65);
this.btnSend.Font = new Font("Segoe UI", 9F, FontStyle.Bold);
this.btnSend.ForeColor = Color.FromArgb(20, 24, 29);
this.btnSend.Inactive1 = Color.FromArgb(93, 203, 173);
this.btnSend.Inactive2 = Color.FromArgb(93, 203, 173);
this.btnSend.Location = new Point(24, 120);
this.btnSend.Name = "btnSend";
this.btnSend.Radius = 5;
this.btnSend.Size = new Size(140, 30);
this.btnSend.Stroke = false;
this.btnSend.StrokeColor = Color.FromArgb(93, 203, 173);
this.btnSend.TabIndex = 4;
this.btnSend.Text = "SEND COMMAND";
this.btnSend.Transparency = false;
this.btnSend.Click += BtnSend_Click;
//
// btnToggleUpdates
//
this.btnToggleUpdates.Active1 = Color.FromArgb(50, 55, 65);
this.btnToggleUpdates.Active2 = Color.FromArgb(50, 55, 65);
this.btnToggleUpdates.BackColor = Color.Transparent;
this.btnToggleUpdates.Cursor = Cursors.Hand;
this.btnToggleUpdates.DialogResult = DialogResult.None;
this.btnToggleUpdates.Disabled1 = Color.FromArgb(32, 35, 45);
this.btnToggleUpdates.Disabled2 = Color.FromArgb(25, 28, 35);
this.btnToggleUpdates.DisabledStrokeColor = Color.FromArgb(50, 55, 65);
this.btnToggleUpdates.Font = new Font("Segoe UI", 9F);
this.btnToggleUpdates.ForeColor = Color.White;
this.btnToggleUpdates.Inactive1 = Color.FromArgb(40, 44, 52);
this.btnToggleUpdates.Inactive2 = Color.FromArgb(40, 44, 52);
this.btnToggleUpdates.Location = new Point(176, 120);
this.btnToggleUpdates.Name = "btnToggleUpdates";
this.btnToggleUpdates.Radius = 5;
this.btnToggleUpdates.Size = new Size(140, 30);
this.btnToggleUpdates.Stroke = true;
this.btnToggleUpdates.StrokeColor = Color.FromArgb(60, 65, 75);
this.btnToggleUpdates.TabIndex = 5;
this.btnToggleUpdates.Text = "Toggle OS Updates";
this.btnToggleUpdates.Transparency = false;
this.btnToggleUpdates.Click += BtnToggleUpdates_Click;
//
// btnClose
//
this.btnClose.Active1 = Color.FromArgb(60, 65, 75);
this.btnClose.Active2 = Color.FromArgb(60, 65, 75);
this.btnClose.BackColor = Color.Transparent;
this.btnClose.Cursor = Cursors.Hand;
this.btnClose.DialogResult = DialogResult.Cancel;
this.btnClose.Disabled1 = Color.FromArgb(32, 35, 45);
this.btnClose.Disabled2 = Color.FromArgb(25, 28, 35);
this.btnClose.DisabledStrokeColor = Color.FromArgb(50, 55, 65);
this.btnClose.Font = new Font("Segoe UI", 9F);
this.btnClose.ForeColor = Color.White;
this.btnClose.Inactive1 = Color.FromArgb(50, 55, 65);
this.btnClose.Inactive2 = Color.FromArgb(50, 55, 65);
this.btnClose.Location = new Point(24, 160);
this.btnClose.Name = "btnClose";
this.btnClose.Radius = 5;
this.btnClose.Size = new Size(292, 30);
this.btnClose.Stroke = true;
this.btnClose.StrokeColor = Color.FromArgb(74, 74, 74);
this.btnClose.TabIndex = 6;
this.btnClose.Text = "Close";
this.btnClose.Transparency = false;
this.btnClose.Click += BtnClose_Click;
//
// AdbCommandForm
//
this.AcceptButton = this.btnSend;
this.AutoScaleDimensions = new SizeF(6F, 13F);
this.AutoScaleMode = AutoScaleMode.Font;
this.BackColor = Color.FromArgb(20, 24, 29);
this.CancelButton = this.btnClose;
this.ClientSize = new Size(340, 210);
this.Controls.Add(this.lblTitle);
this.Controls.Add(this.txtCommand);
this.Controls.Add(this.lblHint);
this.Controls.Add(this.separator);
this.Controls.Add(this.btnSend);
this.Controls.Add(this.btnToggleUpdates);
this.Controls.Add(this.btnClose);
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AdbCommandForm";
this.ShowIcon = false;
this.StartPosition = FormStartPosition.CenterParent;
this.Text = "ADB Command";
this.Load += AdbCommandForm_Load;
this.ResumeLayout(false);
this.PerformLayout();
}
private void AdbCommandForm_Load(object sender, EventArgs e)
{
txtCommand.Focus();
}
private void TxtCommand_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
e.Handled = true;
BtnSend_Click(sender, e);
}
else if (e.KeyChar == (char)Keys.Escape)
{
e.Handled = true;
this.DialogResult = DialogResult.Cancel;
this.Close();
}
}
private void BtnSend_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(txtCommand.Text))
{
return;
}
Command = txtCommand.Text;
ToggleUpdatesClicked = false;
this.DialogResult = DialogResult.OK;
this.Close();
}
private void BtnToggleUpdates_Click(object sender, EventArgs e)
{
// Check current state and set the appropriate command
string adbResult = ADB.RunAdbCommandToString("shell pm list packages -d").Output;
bool isUpdatesDisabled = adbResult.Contains("com.oculus.updater");
if (isUpdatesDisabled)
{
Command = "shell pm enable com.oculus.updater";
}
else
{
Command = "shell pm disable-user --user 0 com.oculus.updater";
}
ToggleUpdatesClicked = true;
this.DialogResult = DialogResult.OK;
this.Close();
}
private void BtnClose_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
private Label lblTitle;
private TextBox txtCommand;
private Label lblHint;
private Panel separator;
private RoundButton btnSend;
private RoundButton btnToggleUpdates;
private RoundButton btnClose;
}
}

View File

@@ -1,72 +0,0 @@
# Run this script as Administrator
# powershell -ExecutionPolicy Bypass -File "C:\RSL\Rookie\AddDefenderExceptions.ps1"
################################################################
## Auto Elevate to Admin if not running as admin
################################################################
# Get the ID and security principal of the current user account
$WindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent()
$WindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal ($WindowsID)
# Get the security principal for the Administrator role
$AdminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator
# Check to see if we are currently running "as Administrator"
if ($WindowsPrincipal.IsInRole($AdminRole)) {
# We are running "as Administrator" - so change the title and background color to indicate this
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + " (Elevated)"
$Host.UI.RawUI.BackgroundColor = "DarkBlue"
Clear-Host
} else {
# We are not running "as Administrator" - so relaunch as administrator
# Create a new process object that starts PowerShell
$NewProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";
# Specify the current script path and name as a parameter
$NewProcess.Arguments = $myInvocation.MyCommand.Definition;
# Indicate that the process should be elevated
$NewProcess.Verb = "runas";
# Start the new process
[System.Diagnostics.Process]::Start($NewProcess);
# Exit from the current unelevated process
exit
}
write-host "Run this script from the directory root with which Rookie will be run"
start-sleep -s 5
$paths = @(
"$PSScriptRoot", # Replaces 'C:\RSL' with the script's root directory
"$PSScriptRoot\rclone",
"$PSScriptRoot\Sideloader Launcher.exe",
"$PSScriptRoot\AndroidSideloader*.exe",
"$PSScriptRoot\rclone\rclone.exe"
)
foreach ($path in $paths) {
try {
Add-MpPreference -ExclusionPath $Path -ErrorAction Stop
Write-Host "Successfully added exclusion for: $path" -ForegroundColor Green
}
catch {
Write-Host "Failed to add exclusion for: $path " -ForegroundColor Red
Write-Host "Error: $_" -ForegroundColor Red
Start-Sleep -s 5
Pause
}
}
# Verify the exclusions
Write-Host "`nCurrent exclusions:" -ForegroundColor Cyan
$defenderPreferences = Get-MpPreference
$paths | ForEach-Object {
if ($defenderPreferences.ExclusionPath -contains $_) {
Write-Host "$_ is already excluded from Defender."
} else {
Write-Host "$_ is NOT excluded from Defender."
}
}
Pause
Start-Sleep -s 5

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="packages\Costura.Fody.5.7.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" />
<Import Project="packages\Costura.Fody.4.1.0\build\Costura.Fody.props" Condition="Exists('packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -15,7 +15,6 @@
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@@ -28,9 +27,9 @@
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup>
<UseShortFileNames>True</UseShortFileNames>
@@ -49,14 +48,14 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<PlatformTarget>x64</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>true</Prefer32Bit>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>icon.ico</ApplicationIcon>
@@ -136,47 +135,23 @@
<ManifestKeyFile>AndroidSideloader_TemporaryKey.pfx</ManifestKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="AdvancedSharpAdbClient, Version=3.5.15.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\AdvancedSharpAdbClient.3.5.15\lib\net45\AdvancedSharpAdbClient.dll</HintPath>
<Reference Include="Costura, Version=4.1.0.0, Culture=neutral, PublicKeyToken=9919ef960d84173d, processorArchitecture=MSIL">
<HintPath>packages\Costura.Fody.4.1.0\lib\net40\Costura.dll</HintPath>
</Reference>
<Reference Include="Costura, Version=5.7.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>packages\Costura.Fody.5.7.0\lib\netstandard1.0\Costura.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.Core, Version=1.0.2478.35, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.WinForms, Version=1.0.2478.35, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.WinForms.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.WebView2.Wpf, Version=1.0.2478.35, Culture=neutral, PublicKeyToken=2a8ab48044d2601e, processorArchitecture=MSIL">
<HintPath>packages\Microsoft.Web.WebView2.1.0.2478.35\lib\net45\Microsoft.Web.WebView2.Wpf.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SergeUtils">
<HintPath>.\SergeUtils.dll</HintPath>
</Reference>
<Reference Include="System">
<HintPath>..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Management" />
<Reference Include="System.Numerics" />
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing">
<HintPath>..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.2\System.Drawing.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
@@ -184,56 +159,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ADB.cs" />
<Compile Include="AdbCommandForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="GalleryView.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ModernListView.cs" />
<Compile Include="ModernProgessBar.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ModernQueuePanel.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="RoundButton.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ColumnSort.cs" />
<Compile Include="Donors.cs" />
<Compile Include="DonorsListView.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="DonorsListView.Designer.cs">
<DependentUpon>DonorsListView.cs</DependentUpon>
</Compile>
<Compile Include="FlexibleMessageBox.cs" />
<Compile Include="RoundedRectangleF.cs" />
<Compile Include="Settings.cs" />
<Compile Include="Sideloader\GetDependencies.cs" />
<Compile Include="Models\PublicConfig.cs" />
<Compile Include="NewApps.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="NewApps.Designer.cs">
<DependentUpon>NewApps.cs</DependentUpon>
</Compile>
<Compile Include="ToggleSwitch.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Transparenter.cs" />
<Compile Include="UpdateForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UpdateForm.Designer.cs">
<DependentUpon>UpdateForm.cs</DependentUpon>
</Compile>
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
@@ -243,8 +170,6 @@
<Compile Include="Sideloader\ProcessOutput.cs" />
<Compile Include="Sideloader\RCLONE.cs" />
<Compile Include="Sideloader\Utilities.cs" />
<Compile Include="Utilities\DnsHelper.cs" />
<Compile Include="Utilities\FileSystemUtilities.cs" />
<Compile Include="Utilities\Logger.cs" />
<Compile Include="QuestForm.cs">
<SubType>Form</SubType>
@@ -260,6 +185,19 @@
<DependentUpon>SettingsForm.cs</DependentUpon>
</Compile>
<Compile Include="Sideloader.cs" />
<Compile Include="spoofer.cs" />
<Compile Include="SpoofForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="SpoofForm.Designer.cs">
<DependentUpon>SpoofForm.cs</DependentUpon>
</Compile>
<Compile Include="ThemeForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ThemeForm.Designer.cs">
<DependentUpon>ThemeForm.cs</DependentUpon>
</Compile>
<Compile Include="Updater.cs" />
<Compile Include="UsernameForm.cs">
<SubType>Form</SubType>
@@ -270,31 +208,22 @@
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SelectFolder.cs" />
<Compile Include="Utilities\SettingsManager.cs" />
<Compile Include="Utilities\StringUtilities.cs" />
<Compile Include="Utilities\GeneralUtilities.cs" />
<Compile Include="Utilities\UpdateGameData.cs" />
<Compile Include="Utilities\UploadGame.cs" />
<Compile Include="Utilities\Zip.cs" />
<Compile Include="Utilities\Metrics.cs" />
<EmbeddedResource Include="DonorsListView.resx">
<DependentUpon>DonorsListView.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="NewApps.resx">
<DependentUpon>NewApps.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UpdateForm.resx">
<DependentUpon>UpdateForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<SubType>Designer</SubType>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<EmbeddedResource Include="QuestForm.resx">
<DependentUpon>QuestForm.cs</DependentUpon>
<SubType>Designer</SubType>
@@ -303,14 +232,18 @@
<DependentUpon>SettingsForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="SpoofForm.resx">
<DependentUpon>SpoofForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="ThemeForm.resx">
<DependentUpon>ThemeForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UsernameForm.resx">
<DependentUpon>UsernameForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<None Include="codenames" />
<None Include=".editorconfig" />
<None Include="packages.config" />
<None Include="Properties\DataSources\AndroidSideloader.Properties.Resources.datasource" />
<None Include="Properties\DataSources\AndroidSideloader.Properties.Settings.datasource" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -320,16 +253,6 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<None Include="Rookie Offline.cmd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="CleanupInstall.cmd">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="AddDefenderExceptions.ps1">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="version" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@@ -337,10 +260,6 @@
<ItemGroup>
<Content Include="changelog.txt" />
<Content Include="icon.ico" />
<Content Include="ChangelogHistory.txt" />
<None Include="Resources\battery.png" />
<None Include="Resources\ajax-loader.gif" />
<None Include="Resources\SearchGlass.PNG" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
@@ -356,14 +275,13 @@
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="packages\Fody.6.0.0\build\Fody.targets" Condition="Exists('packages\Fody.6.0.0\build\Fody.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets'))" />
<Error Condition="!Exists('packages\Fody.6.8.1\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.6.8.1\build\Fody.targets'))" />
<Error Condition="!Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.5.7.0\build\Costura.Fody.props'))" />
<Error Condition="!Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.5.7.0\build\Costura.Fody.targets'))" />
<Error Condition="!Exists('packages\Fody.6.0.0\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Fody.6.0.0\build\Fody.targets'))" />
<Error Condition="!Exists('packages\Costura.Fody.4.1.0\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\Costura.Fody.4.1.0\build\Costura.Fody.props'))" />
</Target>
<PropertyGroup>
<PreBuildEvent>
@@ -373,7 +291,4 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets" Condition="Exists('packages\Microsoft.Web.WebView2.1.0.2478.35\build\Microsoft.Web.WebView2.targets')" />
<Import Project="packages\Fody.6.8.1\build\Fody.targets" Condition="Exists('packages\Fody.6.8.1\build\Fody.targets')" />
<Import Project="packages\Costura.Fody.5.7.0\build\Costura.Fody.targets" Condition="Exists('packages\Costura.Fody.5.7.0\build\Costura.Fody.targets')" />
</Project>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ProjectView>ShowAllFiles</ProjectView>
<PublishUrlHistory>publish\</PublishUrlHistory>
<InstallUrlHistory />
<SupportUrlHistory />
<UpdateUrlHistory />
<BootstrapperUrlHistory />
<ErrorReportUrlHistory />
<FallbackCulture>en-US</FallbackCulture>
<VerifyUploadedFiles>false</VerifyUploadedFiles>
</PropertyGroup>
</Project>

View File

@@ -39,8 +39,8 @@ Global
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|Any CPU.Build.0 = x86|Any CPU
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|x64.ActiveCfg = x86|x64
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|x64.Build.0 = x86|x64
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|x86.ActiveCfg = Release|x86
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|x86.Build.0 = Release|x86
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|x86.ActiveCfg = x86|x86
{CC8BE9F0-CE07-406A-A378-81D9CFE4CC1D}.x86|x86.Build.0 = x86|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,267 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<section name="AndroidSideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
<section name="AndroidADB.Sideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false"/>
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
<userSettings>
<AndroidSideloader.Properties.Settings>
<setting name="checkForUpdates" serializeAs="String">
<value>True</value>
</setting>
<setting name="enableMessageBoxes" serializeAs="String">
<value>True</value>
</setting>
<setting name="firstRun" serializeAs="String">
<value>True</value>
</setting>
<setting name="deleteAllAfterInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="autoUpdateConfig" serializeAs="String">
<value>True</value>
</setting>
<setting name="userJsonOnGameInstall" serializeAs="String">
<value>False</value>
</setting>
<setting name="CallUpgrade" serializeAs="String">
<value>True</value>
</setting>
<setting name="FontStyle" serializeAs="String">
<value>Microsoft Sans Serif, 10pt</value>
</setting>
<setting name="BackPicturePath" serializeAs="String">
<value />
</setting>
<setting name="SpoofGames" serializeAs="String">
<value>False</value>
</setting>
<setting name="BigFontStyle" serializeAs="String">
<value>Microsoft Sans Serif, 14pt</value>
</setting>
<setting name="ResignAPKs" serializeAs="String">
<value>False</value>
</setting>
<setting name="IPAddress" serializeAs="String">
<value />
</setting>
<setting name="InstalledApps" serializeAs="String">
<value />
</setting>
<setting name="ADBPath" serializeAs="String">
<value />
</setting>
<setting name="MainDir" serializeAs="String">
<value />
</setting>
<setting name="delsh" serializeAs="String">
<value>False</value>
</setting>
<setting name="CurrPckg" serializeAs="String">
<value />
</setting>
<setting name="ADBFolder" serializeAs="String">
<value />
</setting>
<setting name="WirelessADB" serializeAs="String">
<value>False</value>
</setting>
<setting name="CurrentGamename" serializeAs="String">
<value />
</setting>
<setting name="PackageNameToCB" serializeAs="String">
<value>False</value>
</setting>
<setting name="DownUpHeld" serializeAs="String">
<value>False</value>
</setting>
<setting name="CurrentLogPath" serializeAs="String">
<value />
</setting>
<setting name="CurrentLogName" serializeAs="String">
<value />
</setting>
<setting name="CurrentCrashPath" serializeAs="String">
<value />
</setting>
<setting name="CurrentCrashName" serializeAs="String">
<value />
</setting>
<setting name="adbdebugwarned" serializeAs="String">
<value>False</value>
</setting>
<setting name="nodevicemode" serializeAs="String">
<value>False</value>
</setting>
<setting name="BMBFchecked" serializeAs="String">
<value>True</value>
</setting>
<setting name="GamesList" serializeAs="String">
<value />
</setting>
<setting name="UploadedGameList" serializeAs="String">
<value>False</value>
</setting>
<setting name="GlobalUsername" serializeAs="String">
<value />
</setting>
<setting name="lastTimeShared" serializeAs="String">
<value />
</setting>
<setting name="AutoReinstall" serializeAs="String">
<value>False</value>
</setting>
<setting name="NonAppPackages" serializeAs="String">
<value />
</setting>
<setting name="LastLaunch" serializeAs="String">
<value>04/20/1969 16:20:00</value>
</setting>
<setting name="SubmittedUpdates" serializeAs="String">
<value />
</setting>
<setting name="ListUpped" serializeAs="String">
<value>False</value>
</setting>
<setting name="LastLaunch2" serializeAs="String">
<value>04/20/1969 16:20:00</value>
</setting>
<setting name="Wired" serializeAs="String">
<value>False</value>
</setting>
<setting name="FontColor" serializeAs="String">
<value>White</value>
</setting>
<setting name="ComboBoxColor" serializeAs="String">
<value>25, 25, 25</value>
</setting>
<setting name="SubButtonColor" serializeAs="String">
<value>42, 45, 58</value>
</setting>
<setting name="TextBoxColor" serializeAs="String">
<value>25, 25, 25</value>
</setting>
<setting name="ButtonColor" serializeAs="String">
<value>32, 35, 45</value>
</setting>
<setting name="BackColor" serializeAs="String">
<value>31, 34, 42</value>
</setting>
<setting name="AppPackages" serializeAs="String">
<value />
</setting>
<setting name="TrailersOn" serializeAs="String">
<value>False</value>
</setting>
<setting name="downloadDir" serializeAs="String">
<value />
</setting>
<setting name="customDownloadDir" serializeAs="String">
<value>False</value>
</setting>
<setting name="customBackupDir" serializeAs="String">
<value>False</value>
</setting>
<setting name="backupDir" serializeAs="String">
<value />
</setting>
<setting name="singleThreadMode" serializeAs="String">
<value>True</value>
</setting>
<setting name="virtualFilesystemCompatibility" serializeAs="String">
<value>False</value>
</setting>
<setting name="UpdateSettings" serializeAs="String">
<value>True</value>
</setting>
<setting name="UUID" serializeAs="String">
<value />
</setting>
<setting name="createPubMirrorFile" serializeAs="String">
<value>True</value>
</setting>
<setting name="useDownloadedFiles" serializeAs="String">
<value>False</value>
</setting>
<setting name="bandwidthLimit" serializeAs="String">
<value>0</value>
</setting>
<setting name="useProxy" serializeAs="String">
<value>False</value>
</setting>
<setting name="proxyAddress" serializeAs="String">
<value />
</setting>
<setting name="proxyPort" serializeAs="String">
<value />
</setting>
<setting name="selectedMirror" serializeAs="String">
<value />
</setting>
</AndroidSideloader.Properties.Settings>
<AndroidADB.Sideloader.Properties.Settings>
<setting name="checkForUpdates" serializeAs="String">
<value>True</value>
</setting>
<setting name="enableMessageBoxes" serializeAs="String">
<value>True</value>
</setting>
<setting name="logRclone" serializeAs="String">
<value>False</value>
</setting>
<setting name="firstRun" serializeAs="String">
<value>True</value>
</setting>
<setting name="deleteAllAfterInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="autoUpdateConfig" serializeAs="String">
<value>True</value>
</setting>
<setting name="singleThreadMode" serializeAs="String">
<value>True</value>
</setting>
<setting name="userJsonOnGameInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="CallUpgrade" serializeAs="String">
<value>True</value>
</setting>
<setting name="BackColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="PanelColor" serializeAs="String">
<value>ActiveCaptionText</value>
</setting>
<setting name="ButtonColor" serializeAs="String">
<value>ActiveCaptionText</value>
</setting>
<setting name="SubButtonColor" serializeAs="String">
<value>64, 64, 64</value>
</setting>
<setting name="TextBoxColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="ComboBoxColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="FontColor" serializeAs="String">
<value>White</value>
</setting>
<setting name="FontStyle" serializeAs="String">
<value>Microsoft Sans Serif, 11.25pt</value>
</setting>
<setting name="BackPicturePath" serializeAs="String">
<value/>
</setting>
<setting name="SpoofGames" serializeAs="String">
<value>False</value>
</setting>
</AndroidADB.Sideloader.Properties.Settings>
</userSettings>
</configuration>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="AndroidSideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
<section name="AndroidADB.Sideloader.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<userSettings>
<AndroidSideloader.Properties.Settings>
<setting name="checkForUpdates" serializeAs="String">
<value>True</value>
</setting>
<setting name="enableMessageBoxes" serializeAs="String">
<value>True</value>
</setting>
<setting name="firstRun" serializeAs="String">
<value>True</value>
</setting>
<setting name="deleteAllAfterInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="autoUpdateConfig" serializeAs="String">
<value>True</value>
</setting>
<setting name="userJsonOnGameInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="CallUpgrade" serializeAs="String">
<value>True</value>
</setting>
<setting name="BackColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="ButtonColor" serializeAs="String">
<value>ActiveCaptionText</value>
</setting>
<setting name="SubButtonColor" serializeAs="String">
<value>64, 64, 64</value>
</setting>
<setting name="TextBoxColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="ComboBoxColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="FontColor" serializeAs="String">
<value>White</value>
</setting>
<setting name="FontStyle" serializeAs="String">
<value>Microsoft Sans Serif, 11.25pt</value>
</setting>
<setting name="BackPicturePath" serializeAs="String">
<value />
</setting>
<setting name="SpoofGames" serializeAs="String">
<value>False</value>
</setting>
<setting name="BandwithLimit" serializeAs="String">
<value />
</setting>
<setting name="BigFontStyle" serializeAs="String">
<value>Microsoft Sans Serif, 16pt</value>
</setting>
<setting name="ResignAPKs" serializeAs="String">
<value>False</value>
</setting>
</AndroidSideloader.Properties.Settings>
<AndroidADB.Sideloader.Properties.Settings>
<setting name="checkForUpdates" serializeAs="String">
<value>True</value>
</setting>
<setting name="enableMessageBoxes" serializeAs="String">
<value>True</value>
</setting>
<setting name="logRclone" serializeAs="String">
<value>False</value>
</setting>
<setting name="firstRun" serializeAs="String">
<value>True</value>
</setting>
<setting name="deleteAllAfterInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="autoUpdateConfig" serializeAs="String">
<value>True</value>
</setting>
<setting name="userJsonOnGameInstall" serializeAs="String">
<value>True</value>
</setting>
<setting name="CallUpgrade" serializeAs="String">
<value>True</value>
</setting>
<setting name="BackColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="PanelColor" serializeAs="String">
<value>ActiveCaptionText</value>
</setting>
<setting name="ButtonColor" serializeAs="String">
<value>ActiveCaptionText</value>
</setting>
<setting name="SubButtonColor" serializeAs="String">
<value>64, 64, 64</value>
</setting>
<setting name="TextBoxColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="ComboBoxColor" serializeAs="String">
<value>45, 45, 45</value>
</setting>
<setting name="FontColor" serializeAs="String">
<value>White</value>
</setting>
<setting name="FontStyle" serializeAs="String">
<value>Microsoft Sans Serif, 11.25pt</value>
</setting>
<setting name="BackPicturePath" serializeAs="String">
<value />
</setting>
<setting name="SpoofGames" serializeAs="String">
<value>False</value>
</setting>
</AndroidADB.Sideloader.Properties.Settings>
</userSettings>
</configuration>

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +0,0 @@
@echo off
echo Killing AndroidSideloader processes...
taskkill /F /FI "IMAGENAME eq AndroidSideloader*" /T
echo Killing adb.exe processes...
taskkill /F /FI "IMAGENAME eq adb.exe" /T
set "folderPath=%userprofile%\AppData\Local\Rookie.WTF\"
echo Deleting contents of %folderPath%...
for /D %%i in ("%folderPath%\*") do (
rd /s /q "%%i"
)
del /q "%folderPath%\*.*"
set "folderPath=%userprofile%\AppData\Local\Rookie.AndroidSideloader\"
echo Deleting contents of %folderPath%...
for /D %%i in ("%folderPath%\*") do (
rd /s /q "%%i"
)
del /q "%folderPath%\*.*"
echo Cleanup complete.
pause

View File

@@ -1,165 +1,105 @@
using System;
using System.Collections;
using System.Collections;
using System.Windows.Forms;
/// <summary>
/// A custom comparer for sorting ListView columns, implementing the 'IComparer' interface.
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
/// <summary>
/// Case-insensitive comparer object used for comparing strings.
/// Specifies the column to be sorted
/// </summary>
private readonly CaseInsensitiveComparer ObjectCompare;
private int ColumnToSort;
/// <summary>
/// Initializes a new instance of the ListViewColumnSorter class and sets default sorting parameters.
/// Specifies the order in which to sort (i.e. 'Ascending').
/// </summary>
private SortOrder OrderOfSort;
/// <summary>
/// Case insensitive comparer object
/// </summary>
private CaseInsensitiveComparer ObjectCompare;
/// <summary>
/// Class constructor. Initializes various elements
/// </summary>
public ListViewColumnSorter()
{
// Default column index for sorting
SortColumn = 0;
// Initialize the column to '0'
ColumnToSort = 0;
// Default sorting order
Order = SortOrder.Ascending;
// Initialize the sort order to 'none'
OrderOfSort = SortOrder.None;
// Initialize the case-insensitive comparer
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new CaseInsensitiveComparer();
}
/// <summary>
/// Compares two ListViewItem objects based on the specified column index and sorting order.
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
/// </summary>
/// <param name="x">First ListViewItem object to compare.</param>
/// <param name="y">Second ListViewItem object to compare.</param>
/// <returns>
/// A signed integer indicating the relative values of x and y:
/// "0" if equal, a negative number if x is less than y, and a positive number if x is greater than y.
/// </returns>
/// <param name="x">First object to be compared</param>
/// <param name="y">Second object to be compared</param>
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
public int Compare(object x, object y)
{
int compareResult;
ListViewItem listviewX = (ListViewItem)x;
ListViewItem listviewY = (ListViewItem)y;
ListViewItem listviewX, listviewY;
// Special handling for column 6 (Popularity ranking)
if (SortColumn == 6)
{
string textX = listviewX.SubItems[SortColumn].Text;
string textY = listviewY.SubItems[SortColumn].Text;
// Extract numeric values from "#1", "#10", etc.
// "-" represents unranked and should go to the end
int rankX = int.MaxValue; // Default for unranked (-)
int rankY = int.MaxValue;
if (textX.StartsWith("#") && int.TryParse(textX.Substring(1), out int parsedX))
{
rankX = parsedX;
}
if (textY.StartsWith("#") && int.TryParse(textY.Substring(1), out int parsedY))
{
rankY = parsedY;
}
// Compare the numeric ranks
compareResult = rankX.CompareTo(rankY);
}
// Special handling for column 5 (Size)
else if (SortColumn == 5)
{
string textX = listviewX.SubItems[SortColumn].Text;
string textY = listviewY.SubItems[SortColumn].Text;
double sizeX = ParseSize(textX);
double sizeY = ParseSize(textY);
// Compare the numeric sizes
compareResult = sizeX.CompareTo(sizeY);
}
else
{
// Default to string comparison for non-numeric columns
compareResult = ObjectCompare.Compare(listviewX.SubItems[SortColumn].Text, listviewY.SubItems[SortColumn].Text);
}
// Determine the return value based on the specified sort order
if (Order == SortOrder.Ascending)
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
// Compare the two items
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
// Calculate correct return value based on object comparison
if (OrderOfSort == SortOrder.Ascending)
{
// Ascending sort is selected, return normal result of compare operation
return compareResult;
}
else if (Order == SortOrder.Descending)
else if (OrderOfSort == SortOrder.Descending)
{
return -compareResult;
// Descending sort is selected, return negative result of compare operation
return (-compareResult);
}
else
{
return 0; // Indicate equality
}
}
/// <summary>
/// Parses a numeric value from a string for accurate numeric comparison.
/// </summary>
/// <param name="text">The string representation of the number.</param>
/// <returns>The parsed integer value; returns 0 if parsing fails.</returns>
private int ParseNumber(string text)
{
// Directly attempt to parse the string as an integer
return int.TryParse(text, out int result) ? result : 0;
}
/// <summary>
/// Parses size strings with units (GB/MB) and converts them to MB for comparison.
/// </summary>
/// <param name="sizeStr">Size string (e.g., "1.23 GB", "123 MB")</param>
/// <returns>Size in MB as a double</returns>
private double ParseSize(string sizeStr)
{
if (string.IsNullOrEmpty(sizeStr))
// Return '0' to indicate they are equal
return 0;
// Remove whitespace
sizeStr = sizeStr.Trim();
// Handle new format: "1.23 GB" or "123 MB"
if (sizeStr.EndsWith(" GB", StringComparison.OrdinalIgnoreCase))
{
string numPart = sizeStr.Substring(0, sizeStr.Length - 3).Trim();
if (double.TryParse(numPart, System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out double gb))
{
return gb * 1024.0; // Convert GB to MB for consistent sorting
}
}
else if (sizeStr.EndsWith(" MB", StringComparison.OrdinalIgnoreCase))
{
string numPart = sizeStr.Substring(0, sizeStr.Length - 3).Trim();
if (double.TryParse(numPart, System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out double mb))
{
return mb;
}
}
// Fallback: try parsing as raw number
if (double.TryParse(sizeStr, System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture, out double rawMb))
{
return rawMb;
}
return 0;
}
/// <summary>
/// Gets or sets the index of the column to be sorted (default is '0').
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
/// </summary>
public int SortColumn { get; set; }
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
/// <summary>
/// Gets or sets the order of sorting (Ascending or Descending).
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
/// </summary>
public SortOrder Order { get; set; }
}
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}

View File

@@ -1,54 +0,0 @@
using System.Collections.Generic;
namespace AndroidSideloader
{
internal class Donors
{
public static int GameNameIndex = 0;
public static int PackageNameIndex = 1;
public static int VersionCodeIndex = 2;
public static int UpdateOrNew = 3;
/* Game Name
* Package Name
* Version Code
* Update or New app
*/
public static List<string> newAppProperties = new List<string>();
public static List<string> donorGameProperties = new List<string>();
public static List<string[]> donorGames = new List<string[]>();
public static List<string[]> newApps = new List<string[]>();
public static void initDonorGames()
{
donorGameProperties.Clear();
donorGames.Clear();
if (!string.IsNullOrEmpty(MainForm.donorApps))
{
string[] gameListSplited = MainForm.donorApps.Split('\n');
foreach (string game in gameListSplited)
{
if (game.Length > 1)
{
donorGames.Add(game.Split(';'));
}
}
}
}
public static void initNewApps()
{
newApps.Clear();
if (!string.IsNullOrEmpty(DonorsListViewForm.newAppsForList))
{
string[] newListSplited = DonorsListViewForm.newAppsForList.Split('\n');
foreach (string game in newListSplited)
{
if (game.Length > 1)
{
newApps.Add(game.Split(';'));
}
}
}
}
}
}

View File

@@ -1,344 +0,0 @@

namespace AndroidSideloader
{
partial class DonorsListViewForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.DonationTimer = new System.Windows.Forms.Timer(this.components);
this.panel1 = new System.Windows.Forms.Panel();
this.skip_forever = new AndroidSideloader.RoundButton();
this.SkipButton = new AndroidSideloader.RoundButton();
this.DonateButton = new AndroidSideloader.RoundButton();
this.panel2 = new System.Windows.Forms.Panel();
this.DonorsListView = new System.Windows.Forms.ListView();
this.GameNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.PackageNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.VersionCodeIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.UpdateOrNew = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.bothdet = new System.Windows.Forms.Label();
this.newdet = new System.Windows.Forms.Label();
this.upddet = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.TimerDesc = new System.Windows.Forms.Label();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.panel1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.panel1.Controls.Add(this.skip_forever);
this.panel1.Controls.Add(this.SkipButton);
this.panel1.Controls.Add(this.DonateButton);
this.panel1.Controls.Add(this.panel2);
this.panel1.Controls.Add(this.bothdet);
this.panel1.Controls.Add(this.newdet);
this.panel1.Controls.Add(this.upddet);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.TimerDesc);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Padding = new System.Windows.Forms.Padding(16);
this.panel1.Size = new System.Drawing.Size(460, 420);
this.panel1.TabIndex = 1;
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// skip_forever
//
this.skip_forever.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
this.skip_forever.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
this.skip_forever.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.skip_forever.BackColor = System.Drawing.Color.Transparent;
this.skip_forever.DialogResult = System.Windows.Forms.DialogResult.OK;
this.skip_forever.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.skip_forever.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.skip_forever.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.skip_forever.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.skip_forever.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.skip_forever.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
this.skip_forever.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
this.skip_forever.Location = new System.Drawing.Point(20, 380);
this.skip_forever.Margin = new System.Windows.Forms.Padding(0);
this.skip_forever.Name = "skip_forever";
this.skip_forever.Radius = 4;
this.skip_forever.Size = new System.Drawing.Size(420, 32);
this.skip_forever.Stroke = true;
this.skip_forever.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.skip_forever.TabIndex = 97;
this.skip_forever.Text = "Add to blacklist / Never ask for the selected apps again";
this.skip_forever.Transparency = false;
this.skip_forever.Click += new System.EventHandler(this.skip_forever_Click);
//
// SkipButton
//
this.SkipButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
this.SkipButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(52)))), ((int)(((byte)(62)))));
this.SkipButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.SkipButton.BackColor = System.Drawing.Color.Transparent;
this.SkipButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.SkipButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.SkipButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.SkipButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.SkipButton.Font = new System.Drawing.Font("Segoe UI Semibold", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.SkipButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.SkipButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
this.SkipButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(35)))), ((int)(((byte)(42)))));
this.SkipButton.Location = new System.Drawing.Point(20, 326);
this.SkipButton.Margin = new System.Windows.Forms.Padding(0);
this.SkipButton.Name = "SkipButton";
this.SkipButton.Radius = 4;
this.SkipButton.Size = new System.Drawing.Size(100, 32);
this.SkipButton.Stroke = true;
this.SkipButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.SkipButton.TabIndex = 96;
this.SkipButton.Text = "Skip";
this.SkipButton.Transparency = false;
this.SkipButton.Click += new System.EventHandler(this.SkipButton_Click);
//
// DonateButton
//
this.DonateButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(140)))), ((int)(((byte)(115)))));
this.DonateButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(125)))), ((int)(((byte)(105)))));
this.DonateButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.DonateButton.BackColor = System.Drawing.Color.Transparent;
this.DonateButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.DonateButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.DonateButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.DonateButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.DonateButton.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold);
this.DonateButton.ForeColor = System.Drawing.Color.White;
this.DonateButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(120)))), ((int)(((byte)(100)))));
this.DonateButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(35)))), ((int)(((byte)(100)))), ((int)(((byte)(85)))));
this.DonateButton.Location = new System.Drawing.Point(128, 326);
this.DonateButton.Margin = new System.Windows.Forms.Padding(0);
this.DonateButton.Name = "DonateButton";
this.DonateButton.Radius = 4;
this.DonateButton.Size = new System.Drawing.Size(312, 32);
this.DonateButton.Stroke = true;
this.DonateButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(150)))), ((int)(((byte)(125)))));
this.DonateButton.TabIndex = 95;
this.DonateButton.Text = "Share Selected Apps";
this.DonateButton.Transparency = false;
this.DonateButton.Click += new System.EventHandler(this.DonateButton_Click);
//
// panel2
//
this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.panel2.Controls.Add(this.DonorsListView);
this.panel2.Location = new System.Drawing.Point(20, 70);
this.panel2.Name = "panel2";
this.panel2.Padding = new System.Windows.Forms.Padding(1);
this.panel2.Size = new System.Drawing.Size(420, 250);
this.panel2.TabIndex = 2;
//
// DonorsListView
//
this.DonorsListView.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
this.DonorsListView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.DonorsListView.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.DonorsListView.CausesValidation = false;
this.DonorsListView.CheckBoxes = true;
this.DonorsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.GameNameIndex,
this.PackageNameIndex,
this.VersionCodeIndex,
this.UpdateOrNew});
this.DonorsListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.DonorsListView.Font = new System.Drawing.Font("Segoe UI", 9.5F);
this.DonorsListView.ForeColor = System.Drawing.Color.White;
this.DonorsListView.FullRowSelect = true;
this.DonorsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.DonorsListView.HideSelection = false;
this.DonorsListView.Location = new System.Drawing.Point(1, 1);
this.DonorsListView.MinimumSize = new System.Drawing.Size(100, 100);
this.DonorsListView.Name = "DonorsListView";
this.DonorsListView.Size = new System.Drawing.Size(418, 248);
this.DonorsListView.TabIndex = 0;
this.DonorsListView.UseCompatibleStateImageBehavior = false;
this.DonorsListView.View = System.Windows.Forms.View.Details;
this.DonorsListView.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.DonorsListView_ItemChecked);
this.DonorsListView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.DonorsListView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.DonorsListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// GameNameIndex
//
this.GameNameIndex.Text = "App Name";
this.GameNameIndex.Width = 220;
//
// PackageNameIndex
//
this.PackageNameIndex.DisplayIndex = 2;
this.PackageNameIndex.Text = "Package";
this.PackageNameIndex.Width = 0;
//
// VersionCodeIndex
//
this.VersionCodeIndex.DisplayIndex = 3;
this.VersionCodeIndex.Text = "Version";
this.VersionCodeIndex.Width = 100;
//
// UpdateOrNew
//
this.UpdateOrNew.DisplayIndex = 1;
this.UpdateOrNew.Text = "Type";
this.UpdateOrNew.Width = 80;
//
// bothdet
//
this.bothdet.AutoSize = true;
this.bothdet.BackColor = System.Drawing.Color.Transparent;
this.bothdet.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.bothdet.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.bothdet.Location = new System.Drawing.Point(20, 15);
this.bothdet.Name = "bothdet";
this.bothdet.Size = new System.Drawing.Size(228, 20);
this.bothdet.TabIndex = 3;
this.bothdet.Text = "Updates && New Apps Available";
this.bothdet.Visible = false;
this.bothdet.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.bothdet.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.bothdet.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// newdet
//
this.newdet.AutoSize = true;
this.newdet.BackColor = System.Drawing.Color.Transparent;
this.newdet.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.newdet.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.newdet.Location = new System.Drawing.Point(20, 15);
this.newdet.Name = "newdet";
this.newdet.Size = new System.Drawing.Size(149, 20);
this.newdet.TabIndex = 3;
this.newdet.Text = "New Apps Available";
this.newdet.Visible = false;
this.newdet.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.newdet.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.newdet.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// upddet
//
this.upddet.AutoSize = true;
this.upddet.BackColor = System.Drawing.Color.Transparent;
this.upddet.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.upddet.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.upddet.Location = new System.Drawing.Point(20, 15);
this.upddet.Name = "upddet";
this.upddet.Size = new System.Drawing.Size(135, 20);
this.upddet.TabIndex = 3;
this.upddet.Text = "Updates Available";
this.upddet.Visible = false;
this.upddet.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.upddet.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.upddet.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// label2
//
this.label2.AutoSize = true;
this.label2.BackColor = System.Drawing.Color.Transparent;
this.label2.Font = new System.Drawing.Font("Segoe UI", 9F);
this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.label2.Location = new System.Drawing.Point(20, 42);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(338, 15);
this.label2.TabIndex = 3;
this.label2.Text = "All apps are donated by users! Help the community by sharing.";
this.label2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.label2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.label2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// TimerDesc
//
this.TimerDesc.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.TimerDesc.AutoSize = true;
this.TimerDesc.BackColor = System.Drawing.Color.Transparent;
this.TimerDesc.Font = new System.Drawing.Font("Segoe UI", 8F);
this.TimerDesc.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(125)))), ((int)(((byte)(135)))));
this.TimerDesc.Location = new System.Drawing.Point(79, 362);
this.TimerDesc.Name = "TimerDesc";
this.TimerDesc.Size = new System.Drawing.Size(292, 13);
this.TimerDesc.TabIndex = 3;
this.TimerDesc.Text = "Don\'t share free apps. Upload happens in background.";
this.TimerDesc.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.TimerDesc.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.TimerDesc.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
//
// DonorsListViewForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.ClientSize = new System.Drawing.Size(460, 420);
this.ControlBox = false;
this.Controls.Add(this.panel1);
this.ForeColor = System.Drawing.Color.White;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "DonorsListViewForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Load += new System.EventHandler(this.DonorsListViewForm_Load);
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.DonorsListViewForm_MouseUp);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListView DonorsListView;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Label TimerDesc;
private System.Windows.Forms.ColumnHeader GameNameIndex;
private System.Windows.Forms.ColumnHeader PackageNameIndex;
private System.Windows.Forms.ColumnHeader VersionCodeIndex;
private System.Windows.Forms.ColumnHeader UpdateOrNew;
public System.Windows.Forms.Timer DonationTimer;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label bothdet;
private System.Windows.Forms.Label newdet;
private System.Windows.Forms.Label upddet;
private System.Windows.Forms.Panel panel2;
private RoundButton DonateButton;
private RoundButton SkipButton;
private RoundButton skip_forever;
}
}

View File

@@ -1,324 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class DonorsListViewForm : Form
{
// Modern theme colors
private static readonly Color BackgroundColor = Color.FromArgb(20, 24, 29);
private static readonly Color BorderColor = Color.FromArgb(70, 80, 100);
private static readonly Color UpdateHighlightColor = Color.FromArgb(0, 79, 97);
// Shadow and corner settings
private const int CS_DROPSHADOW = 0x00020000;
private const int WM_NCLBUTTONDOWN = 0xA1;
private const int HT_CAPTION = 0x2;
private const int SHADOW_SIZE = 2;
private const int CONTENT_RADIUS = 10;
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool ReleaseCapture();
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CS_DROPSHADOW;
return cp;
}
}
public DonorsListViewForm()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
ApplyModernTheme();
CenterToScreen();
Donors.initDonorGames();
var seen = new HashSet<string>();
var DGameList = new List<ListViewItem>();
foreach (string[] release in Donors.donorGames)
{
if (release.Length == 0) continue;
string key = release[0];
if (seen.Add(key))
{
DGameList.Add(new ListViewItem(release));
}
}
ListViewItem[] arr = DGameList.ToArray();
DonorsListView.BeginUpdate();
DonorsListView.Items.Clear();
DonorsListView.Items.AddRange(arr);
DonorsListView.EndUpdate();
}
private void ApplyModernTheme()
{
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.FromArgb(25, 25, 30);
this.Padding = new Padding(5);
panel1.BackColor = BackgroundColor;
panel1.Location = new Point(6, 6);
panel1.Size = new Size(this.ClientSize.Width - 12, this.ClientSize.Height - 12);
panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
this.Paint += Form_Paint;
// Close button
var closeButton = new Button
{
Text = "✕",
Font = new Font("Segoe UI", 9F),
ForeColor = Color.White,
BackColor = BackgroundColor,
FlatStyle = FlatStyle.Flat,
Size = new Size(30, 28),
Location = new Point(panel1.Width - 35, 5),
Cursor = Cursors.Hand,
TabStop = false
};
closeButton.FlatAppearance.BorderSize = 0;
closeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(200, 60, 60);
closeButton.Click += (s, e) => Close();
panel1.Controls.Add(closeButton);
closeButton.BringToFront();
// Enable dragging
panel1.MouseDown += TitleArea_MouseDown;
foreach (Control ctrl in panel1.Controls)
{
if (ctrl is Label)
{
ctrl.MouseDown += TitleArea_MouseDown;
}
}
}
private void TitleArea_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(this.Handle, WM_NCLBUTTONDOWN, (IntPtr)HT_CAPTION, IntPtr.Zero);
}
}
private void Form_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int w = this.Width;
int h = this.Height;
// Draw shadow layers
for (int i = SHADOW_SIZE; i >= 1; i--)
{
int alpha = (SHADOW_SIZE - i + 1) * 12;
Rectangle shadowRect = new Rectangle(
SHADOW_SIZE - i,
SHADOW_SIZE - i,
w - (SHADOW_SIZE - i) * 2 - 1,
h - (SHADOW_SIZE - i) * 2 - 1);
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 0, 0, 0), 1))
using (GraphicsPath shadowPath = CreateRoundedRectPath(shadowRect, CONTENT_RADIUS + i))
{
e.Graphics.DrawPath(shadowPen, shadowPath);
}
}
// Draw content background
Rectangle contentRect = new Rectangle(SHADOW_SIZE, SHADOW_SIZE, w - SHADOW_SIZE * 2, h - SHADOW_SIZE * 2);
using (GraphicsPath contentPath = CreateRoundedRectPath(contentRect, CONTENT_RADIUS))
{
using (SolidBrush bgBrush = new SolidBrush(BackgroundColor))
{
e.Graphics.FillPath(bgBrush, contentPath);
}
using (Pen borderPen = new Pen(BorderColor, 1f))
{
e.Graphics.DrawPath(borderPen, contentPath);
}
}
// Apply rounded region
using (GraphicsPath regionPath = CreateRoundedRectPath(new Rectangle(0, 0, w, h), CONTENT_RADIUS + SHADOW_SIZE))
{
this.Region = new Region(regionPath);
}
}
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
{
GraphicsPath path = new GraphicsPath();
if (radius <= 0)
{
path.AddRectangle(rect);
return path;
}
int diameter = Math.Min(radius * 2, Math.Min(rect.Width, rect.Height));
radius = diameter / 2;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
path.AddArc(arcRect, 180, 90);
arcRect.X = rect.Right - diameter;
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter;
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left;
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
public static string DonorsLocal = MainForm.donorApps;
public static bool ifuploads = false;
public static string newAppsForList = "";
private void DonorsListViewForm_Load(object sender, EventArgs e)
{
MainForm.updatesNotified = true;
bothdet.Visible = MainForm.updates && MainForm.newapps;
upddet.Visible = MainForm.updates && !MainForm.newapps;
newdet.Visible = !MainForm.updates;
foreach (ListViewItem listItem in DonorsListView.Items)
{
if (listItem.SubItems[Donors.UpdateOrNew].Text.Contains("Update"))
listItem.BackColor = UpdateHighlightColor;
}
}
private async void DonateButton_Click(object sender, EventArgs e)
{
if (DonorsListView.CheckedItems.Count > 0)
{
bool uncheckednewapps = false;
foreach (ListViewItem listItem in DonorsListView.Items)
{
if (!listItem.Checked && listItem.SubItems[Donors.UpdateOrNew].Text.Contains("New"))
{
uncheckednewapps = true;
newAppsForList += listItem.SubItems[Donors.GameNameIndex].Text + ";" + listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
}
}
if (uncheckednewapps)
{
new NewApps().ShowDialog();
Hide();
}
else
{
Hide();
}
for (int i = 0; i < DonorsListView.CheckedItems.Count; i++)
{
ulong vcode = Convert.ToUInt64(DonorsListView.CheckedItems[i].SubItems[Donors.VersionCodeIndex].Text);
bool isUpdate = DonorsListView.CheckedItems[i].SubItems[Donors.UpdateOrNew].Text.Contains("Update");
await Program.form.extractAndPrepareGameToUploadAsync(
DonorsListView.CheckedItems[i].SubItems[Donors.GameNameIndex].Text,
DonorsListView.CheckedItems[i].SubItems[Donors.PackageNameIndex].Text,
vcode, isUpdate);
ifuploads = true;
}
}
if (ifuploads) MainForm.doUpload();
Close();
}
private void DonorsListView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
SkipButton.Enabled = DonorsListView.CheckedItems.Count == 0;
DonateButton.Enabled = !SkipButton.Enabled;
skip_forever.Enabled = DonorsListView.CheckedItems.Count > 0;
}
private void SkipButton_Click(object sender, EventArgs e)
{
foreach (ListViewItem listItem in DonorsListView.Items)
{
if (!listItem.Checked && listItem.SubItems[Donors.UpdateOrNew].Text.Contains("New"))
newAppsForList += listItem.SubItems[Donors.GameNameIndex].Text + ";" + listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
}
if (!string.IsNullOrEmpty(newAppsForList))
new NewApps().ShowDialog();
Close();
}
private void DonorsListViewForm_MouseDown(object sender, MouseEventArgs e) => TitleArea_MouseDown(sender, e);
private void DonorsListViewForm_MouseMove(object sender, MouseEventArgs e) { }
private void DonorsListViewForm_MouseUp(object sender, MouseEventArgs e) { }
private void skip_forever_Click(object sender, EventArgs e)
{
var appsToBlacklist = DonorsListView.CheckedItems.Cast<ListViewItem>()
.Select(item => item.SubItems[Donors.PackageNameIndex].Text).ToList();
if (appsToBlacklist.Count == 0)
{
MessageBox.Show("No apps selected to blacklist.", "Info", MessageBoxButtons.OK);
return;
}
if (MessageBox.Show(
$"Permanently skip donation requests for {appsToBlacklist.Count} app(s)?",
"Confirm Blacklist", MessageBoxButtons.YesNo, MessageBoxIcon.Question) != DialogResult.Yes)
return;
string blacklistPath = Path.Combine(Environment.CurrentDirectory, "blacklist.json");
try
{
var existingBlacklist = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (File.Exists(blacklistPath))
{
var jsonArray = Newtonsoft.Json.JsonConvert.DeserializeObject<string[]>(File.ReadAllText(blacklistPath));
if (jsonArray != null)
foreach (string entry in jsonArray.Where(ee => !string.IsNullOrWhiteSpace(ee)))
existingBlacklist.Add(entry.Trim());
}
foreach (string pkg in appsToBlacklist) existingBlacklist.Add(pkg);
File.WriteAllText(blacklistPath, Newtonsoft.Json.JsonConvert.SerializeObject(existingBlacklist.ToArray(), Newtonsoft.Json.Formatting.Indented));
Logger.Log($"Added {appsToBlacklist.Count} apps to local blacklist");
MessageBox.Show($"{appsToBlacklist.Count} {(appsToBlacklist.Count == 1 ? "app" : "apps")} added to blacklist.",
"Success",
MessageBoxButtons.OK, MessageBoxIcon.Information);
Close();
}
catch (Exception ex)
{
Logger.Log($"Error saving blacklist: {ex.Message}", LogLevel.ERROR);
MessageBox.Show($"Error: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

674
LICENSE
View File

@@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

2697
MainForm.Designer.cs generated

File diff suppressed because it is too large Load Diff

10252
MainForm.cs Executable file → Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -117,73 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="speedLabel_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1165, 17</value>
</metadata>
<metadata name="startsideloadbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>966, 17</value>
</metadata>
<metadata name="devicesbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>705, 91</value>
</metadata>
<metadata name="obbcopybutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>526, 91</value>
</metadata>
<metadata name="backupadbbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>390, 17</value>
</metadata>
<metadata name="backupbutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>355, 91</value>
</metadata>
<metadata name="restorebutton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>187, 91</value>
</metadata>
<metadata name="getApkButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 91</value>
</metadata>
<metadata name="uninstallAppButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1157, 54</value>
</metadata>
<metadata name="pullAppToDesktopBtn_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>945, 54</value>
</metadata>
<metadata name="copyBulkObbButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>741, 54</value>
</metadata>
<metadata name="aboutBtn_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>876, 91</value>
</metadata>
<metadata name="settingsButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>568, 54</value>
</metadata>
<metadata name="QuestOptionsButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>223, 54</value>
</metadata>
<metadata name="btnOpenDownloads_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>764, 17</value>
</metadata>
<metadata name="btnRunAdbCmd_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>581, 17</value>
</metadata>
<metadata name="ADBWirelessToggle_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="UpdateGamesButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 54</value>
</metadata>
<metadata name="listApkButton_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1320, 17</value>
</metadata>
<metadata name="etaLabel_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>428, 54</value>
</metadata>
<metadata name="favoriteGame.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>1021, 91</value>
</metadata>
<metadata name="btnViewToggle_Tooltip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>215, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>113</value>
</metadata>
</root>

View File

@@ -1,22 +0,0 @@
using Newtonsoft.Json;
using System;
using System.Text;
namespace AndroidSideloader.Models
{
[JsonObject(MemberSerialization.OptIn)]
public class PublicConfig
{
[JsonProperty("baseUri")]
public string BaseUri { get; set; }
private string password;
[JsonProperty("password")]
public string Password
{
get => password;
set => password = Encoding.UTF8.GetString(Convert.FromBase64String(value));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,439 +0,0 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AndroidSideloader
{
// A modern progress bar with rounded corners, left-to-right gradient fill,
// animated indeterminate mode, and optional status text overlay
[Description("Modern Themed Progress Bar")]
public class ModernProgressBar : Control
{
#region Fields
private float _value;
private float _minimum;
private float _maximum = 100f;
private int _radius = 8;
private bool _isIndeterminate;
private string _statusText = string.Empty;
private string _operationType = string.Empty;
// Indeterminate animation
private readonly Timer _animationTimer;
private float _animationOffset;
private const float AnimationSpeed = 4f;
private const int IndeterminateBlockWidth = 80;
// Colors
private Color _backgroundColor = Color.FromArgb(28, 32, 38);
private Color _progressStartColor = Color.FromArgb(120, 220, 190); // lighter accent
private Color _progressEndColor = Color.FromArgb(50, 160, 130); // darker accent
private Color _indeterminateColor = Color.FromArgb(93, 203, 173); // accent
private Color _textColor = Color.FromArgb(230, 230, 230);
private Color _textShadowColor = Color.FromArgb(90, 0, 0, 0);
#endregion
#region Constructor
public ModernProgressBar()
{
SetStyle(
ControlStyles.AllPaintingInWmPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint |
ControlStyles.SupportsTransparentBackColor,
true);
BackColor = Color.Transparent;
// Size + Font
Height = 28;
Width = 220;
Font = new Font("Segoe UI", 9f, FontStyle.Bold);
_animationTimer = new Timer { Interval = 16 }; // ~60fps
_animationTimer.Tick += AnimationTimer_Tick;
}
#endregion
#region Properties
[Category("Progress")]
[Description("The current value of the progress bar.")]
public float Value
{
get => _value;
set
{
_value = Math.Max(_minimum, Math.Min(_maximum, value));
Invalidate();
}
}
[Category("Progress")]
[Description("The minimum value of the progress bar.")]
public float Minimum
{
get => _minimum;
set
{
_minimum = value;
if (_value < _minimum) _value = _minimum;
Invalidate();
}
}
[Category("Progress")]
[Description("The maximum value of the progress bar.")]
public float Maximum
{
get => _maximum;
set
{
_maximum = value;
if (_value > _maximum) _value = _maximum;
Invalidate();
}
}
[Category("Appearance")]
[Description("The corner radius of the progress bar.")]
public int Radius
{
get => _radius;
set
{
_radius = Math.Max(0, value);
Invalidate();
}
}
[Category("Progress")]
[Description("Whether the progress bar shows indeterminate (marquee) progress.")]
public bool IsIndeterminate
{
get => _isIndeterminate;
set
{
// If there is no change, do nothing
if (_isIndeterminate == value)
return;
_isIndeterminate = value;
if (_isIndeterminate)
{
_animationOffset = -IndeterminateBlockWidth;
_animationTimer.Start();
}
else
{
_animationTimer.Stop();
}
Invalidate();
}
}
[Category("Appearance")]
[Description("Optional status text to display on the progress bar.")]
public string StatusText
{
get => _statusText;
set
{
_statusText = value ?? string.Empty;
Invalidate();
}
}
[Category("Appearance")]
[Description("Operation type label (e.g., 'Downloading', 'Installing').")]
public string OperationType
{
get => _operationType;
set
{
_operationType = value ?? string.Empty;
Invalidate();
}
}
[Category("Appearance")]
[Description("Background color of the progress bar track.")]
public Color BackgroundColor
{
get => _backgroundColor;
set { _backgroundColor = value; Invalidate(); }
}
[Category("Appearance")]
[Description("Start color of the progress gradient (left side).")]
public Color ProgressStartColor
{
get => _progressStartColor;
set { _progressStartColor = value; Invalidate(); }
}
[Category("Appearance")]
[Description("End color of the progress gradient (right side).")]
public Color ProgressEndColor
{
get => _progressEndColor;
set { _progressEndColor = value; Invalidate(); }
}
[Category("Appearance")]
[Description("Color used for indeterminate animation.")]
public Color IndeterminateColor
{
get => _indeterminateColor;
set { _indeterminateColor = value; Invalidate(); }
}
[Category("Appearance")]
[Description("Text color for status overlay.")]
public Color TextColor
{
get => _textColor;
set { _textColor = value; Invalidate(); }
}
// Gets the progress as a percentage (0-100)
public float ProgressPercent =>
_maximum > _minimum ? (_value - _minimum) / (_maximum - _minimum) * 100f : 0f;
#endregion
#region Painting
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.Clear(BackColor);
int w = ClientSize.Width;
int h = ClientSize.Height;
if (w <= 0 || h <= 0) return;
var outerRect = new Rectangle(0, 0, w - 1, h - 1);
// Draw background track
using (var path = CreateRoundedPath(outerRect, _radius))
using (var bgBrush = new SolidBrush(_backgroundColor))
{
g.FillPath(bgBrush, path);
}
// Draw progress or indeterminate animation
if (_isIndeterminate)
{
DrawIndeterminate(g, outerRect);
}
else if (_value > _minimum)
{
DrawProgress(g, outerRect);
}
// Draw text overlay
DrawTextOverlay(g, outerRect);
base.OnPaint(e);
}
private void DrawProgress(Graphics g, Rectangle outerRect)
{
float percent = (_maximum > _minimum)
? (_value - _minimum) / (_maximum - _minimum)
: 0f;
if (percent <= 0f) return;
if (percent > 1f) percent = 1f;
int progressWidth = (int)Math.Round(outerRect.Width * percent);
if (progressWidth <= 0) return;
if (progressWidth > outerRect.Width) progressWidth = outerRect.Width;
using (var outerPath = CreateRoundedPath(outerRect, _radius))
{
// Clip to progress area inside rounded track
Rectangle progressRect = new Rectangle(outerRect.X, outerRect.Y, progressWidth, outerRect.Height);
using (var progressClip = new Region(progressRect))
using (var trackRegion = new Region(outerPath))
{
trackRegion.Intersect(progressClip);
Region prevClip = g.Clip;
try
{
g.SetClip(trackRegion, CombineMode.Replace);
// Left-to-right gradient, based on accent color
using (var gradientBrush = new LinearGradientBrush(
progressRect,
_progressStartColor,
_progressEndColor,
LinearGradientMode.Horizontal))
{
g.FillPath(gradientBrush, outerPath);
}
}
finally
{
g.Clip = prevClip;
}
}
}
}
private void DrawIndeterminate(Graphics g, Rectangle outerRect)
{
using (var outerPath = CreateRoundedPath(outerRect, _radius))
{
Region prevClip = g.Clip;
try
{
g.SetClip(outerPath, CombineMode.Replace);
int blockWidth = Math.Min(IndeterminateBlockWidth, outerRect.Width);
int blockX = (int)_animationOffset;
var blockRect = new Rectangle(blockX, outerRect.Y, blockWidth, outerRect.Height);
// Solid bar with slight left-to-right gradient
using (var brush = new LinearGradientBrush(
blockRect,
ControlPaint.Light(_indeterminateColor, 0.1f),
ControlPaint.Dark(_indeterminateColor, 0.1f),
LinearGradientMode.Horizontal))
{
g.FillRectangle(brush, blockRect);
}
}
finally
{
g.Clip = prevClip;
}
}
}
private void DrawTextOverlay(Graphics g, Rectangle outerRect)
{
string displayText = BuildDisplayText();
if (string.IsNullOrEmpty(displayText)) return;
using (var sf = new StringFormat
{
Alignment = StringAlignment.Center,
LineAlignment = StringAlignment.Center,
Trimming = StringTrimming.EllipsisCharacter
})
{
// Slight shadow for legibility on accent background
var shadowRect = new Rectangle(outerRect.X + 1, outerRect.Y + 1, outerRect.Width, outerRect.Height);
using (var shadowBrush = new SolidBrush(_textShadowColor))
{
g.DrawString(displayText, Font, shadowBrush, shadowRect, sf);
}
using (var textBrush = new SolidBrush(_textColor))
{
g.DrawString(displayText, Font, textBrush, outerRect, sf);
}
}
}
private string BuildDisplayText()
{
if (!string.IsNullOrEmpty(_statusText))
{
return _statusText;
}
if (_isIndeterminate && !string.IsNullOrEmpty(_operationType))
{
// E.g. "Downloading..."
return _operationType + "...";
}
if (!_isIndeterminate && _value > _minimum)
{
// Show one decimal place for sub-percent precision
string percentText = $"{ProgressPercent:0.0}%";
if (!string.IsNullOrEmpty(_operationType))
{
// E.g. "Downloading · 73.5%"
return $"{_operationType} · {percentText}";
}
return percentText;
}
return string.Empty;
}
private GraphicsPath CreateRoundedPath(Rectangle rect, int radius)
{
var path = new GraphicsPath();
if (radius <= 0)
{
path.AddRectangle(rect);
return path;
}
int diameter = radius * 2;
diameter = Math.Min(diameter, Math.Min(rect.Width, rect.Height));
radius = diameter / 2;
var arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
path.AddArc(arcRect, 180, 90);
arcRect.X = rect.Right - diameter;
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter;
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left;
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
#endregion
#region Animation
private void AnimationTimer_Tick(object sender, EventArgs e)
{
_animationOffset += AnimationSpeed;
if (_animationOffset > ClientSize.Width + IndeterminateBlockWidth)
{
_animationOffset = -IndeterminateBlockWidth;
}
Invalidate();
}
#endregion
#region Cleanup
protected override void Dispose(bool disposing)
{
if (disposing)
{
_animationTimer?.Stop();
_animationTimer?.Dispose();
}
base.Dispose(disposing);
}
#endregion
}
}

View File

@@ -1,511 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AndroidSideloader
{
// Modern download queue panel with drag-reorder, cancel buttons
// and custom scrollbar with auto-scrolling during drag
public sealed class ModernQueuePanel : Control
{
// Layout constants
private const int ItemHeight = 28, ItemMargin = 4, ItemRadius = 5;
private const int XButtonSize = 18, DragHandleWidth = 20, TextPadding = 6;
private const int ScrollbarWidth = 6, ScrollbarWidthHover = 8, ScrollbarMargin = 2;
private const int ScrollbarRadius = 3, MinThumbHeight = 20;
private const int AutoScrollZoneHeight = 30, AutoScrollSpeed = 3;
// Color palette
private static readonly Color BgColor = Color.FromArgb(24, 26, 30);
private static readonly Color ItemBg = Color.FromArgb(32, 36, 44);
private static readonly Color ItemHoverBg = Color.FromArgb(42, 46, 54);
private static readonly Color ItemDragBg = Color.FromArgb(45, 55, 70);
private static readonly Color TextColor = Color.FromArgb(210, 210, 210);
private static readonly Color TextDimColor = Color.FromArgb(140, 140, 140);
private static readonly Color AccentColor = Color.FromArgb(93, 203, 173);
private static readonly Color XButtonBg = Color.FromArgb(55, 60, 70);
private static readonly Color XButtonHoverBg = Color.FromArgb(200, 60, 60);
private static readonly Color GripColor = Color.FromArgb(70, 75, 85);
private static readonly Color ItemDragBorder = Color.FromArgb(55, 65, 80);
private static readonly Color ScrollTrackColor = Color.FromArgb(35, 38, 45);
private static readonly Color ScrollThumbColor = Color.FromArgb(70, 75, 85);
private static readonly Color ScrollThumbHoverColor = Color.FromArgb(90, 95, 105);
private static readonly Color ScrollThumbDragColor = Color.FromArgb(110, 115, 125);
private readonly List<string> _items = new List<string>();
private readonly Timer _autoScrollTimer;
// State tracking
private int _hoveredIndex = -1, _dragIndex = -1, _dropIndex = -1, _scrollOffset;
private bool _hoveringX, _scrollbarHovered, _scrollbarDragging;
private int _scrollDragStartY, _scrollDragStartOffset, _autoScrollDirection;
private Rectangle _scrollThumbRect, _scrollTrackRect;
public event EventHandler<int> ItemRemoved;
public event EventHandler<ReorderEventArgs> ItemReordered;
public ModernQueuePanel()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
BackColor = BgColor;
_autoScrollTimer = new Timer { Interval = 16 }; // ~60 FPS
_autoScrollTimer.Tick += (s, e) => HandleAutoScroll();
}
public bool IsDownloading { get; set; }
public int Count => _items.Count;
private int ContentHeight => _items.Count * (ItemHeight + ItemMargin) + ItemMargin;
private int MaxScroll => Math.Max(0, ContentHeight - Height);
private bool ScrollbarVisible => ContentHeight > Height;
public void SetItems(IEnumerable<string> items)
{
_items.Clear();
_items.AddRange(items);
ResetState();
}
private void ResetState()
{
_hoveredIndex = _dragIndex = -1;
ClampScroll();
Invalidate();
}
private void ClampScroll() =>
_scrollOffset = Math.Max(0, Math.Min(MaxScroll, _scrollOffset));
// Auto-scroll when dragging near edges
private void HandleAutoScroll()
{
if (_dragIndex < 0 || _autoScrollDirection == 0)
{
_autoScrollTimer.Stop();
return;
}
int oldOffset = _scrollOffset;
_scrollOffset += _autoScrollDirection * AutoScrollSpeed;
ClampScroll();
if (_scrollOffset != oldOffset)
{
UpdateDropIndex(PointToClient(MousePosition).Y);
Invalidate();
}
}
private void UpdateAutoScroll(int mouseY)
{
if (_dragIndex < 0 || MaxScroll <= 0)
{
StopAutoScroll();
return;
}
_autoScrollDirection = mouseY < AutoScrollZoneHeight && _scrollOffset > 0 ? -1 :
mouseY > Height - AutoScrollZoneHeight && _scrollOffset < MaxScroll ? 1 : 0;
if (_autoScrollDirection != 0 && !_autoScrollTimer.Enabled)
_autoScrollTimer.Start();
else if (_autoScrollDirection == 0)
_autoScrollTimer.Stop();
}
private void StopAutoScroll()
{
_autoScrollDirection = 0;
_autoScrollTimer.Stop();
}
private void UpdateDropIndex(int mouseY) =>
_dropIndex = Math.Max(1, Math.Min(_items.Count, (mouseY + _scrollOffset + ItemHeight / 2) / (ItemHeight + ItemMargin)));
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Clear(BgColor);
if (_items.Count == 0)
{
DrawEmptyState(g);
return;
}
// Draw visible items
for (int i = 0; i < _items.Count; i++)
{
var rect = GetItemRect(i);
if (rect.Bottom >= 0 && rect.Top <= Height)
DrawItem(g, i, rect);
}
// Draw drop indicator and scrollbar
if (_dragIndex >= 0 && _dropIndex >= 0 && _dropIndex != _dragIndex)
DrawDropIndicator(g);
if (ScrollbarVisible)
DrawScrollbar(g);
}
private void DrawEmptyState(Graphics g)
{
using (var brush = new SolidBrush(TextDimColor))
using (var font = new Font("Segoe UI", 8.5f, FontStyle.Italic))
{
var sf = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
g.DrawString("Queue is empty", font, brush, ClientRectangle, sf);
}
}
private void DrawItem(Graphics g, int index, Rectangle rect)
{
bool isFirst = index == 0;
bool isDragging = index == _dragIndex;
bool isHovered = !isDragging && index == _hoveredIndex;
Color bg = isDragging ? ItemDragBg : isHovered ? ItemHoverBg : ItemBg;
// Draw item background
using (var path = CreateRoundedRect(rect, ItemRadius))
using (var brush = new SolidBrush(bg))
g.FillPath(brush, path);
// Active download (first item) gets gradient accent and border
if (isFirst)
DrawFirstItemAccent(g, rect);
// Dragged items get subtle highlight border
else if (isDragging)
DrawBorder(g, rect, ItemDragBorder, 0.5f);
// Draw drag handle, text, and close button
if (!isFirst)
DrawDragHandle(g, rect);
DrawItemText(g, index, rect, isFirst);
DrawXButton(g, rect, isHovered && _hoveringX);
}
// Draw gradient accent and border for active download (first item)
private void DrawFirstItemAccent(Graphics g, Rectangle rect)
{
using (var path = CreateRoundedRect(rect, ItemRadius))
using (var gradBrush = new LinearGradientBrush(rect,
Color.FromArgb(60, AccentColor), Color.FromArgb(0, AccentColor), LinearGradientMode.Horizontal))
{
var oldClip = g.Clip;
g.SetClip(path);
g.FillRectangle(gradBrush, rect);
g.Clip = oldClip;
}
DrawBorder(g, rect, AccentColor, 1.5f);
}
private void DrawBorder(Graphics g, Rectangle rect, Color color, float width)
{
using (var path = CreateRoundedRect(rect, ItemRadius))
using (var pen = new Pen(color, width))
g.DrawPath(pen, path);
}
private void DrawDragHandle(Graphics g, Rectangle rect)
{
int cx = rect.X + 8, cy = rect.Y + rect.Height / 2;
using (var brush = new SolidBrush(GripColor))
{
for (int row = -1; row <= 1; row++)
for (int col = 0; col < 2; col++)
g.FillEllipse(brush, cx + col * 4, cy + row * 4 - 1, 2, 2);
}
}
private void DrawItemText(Graphics g, int index, Rectangle rect, bool isFirst)
{
int textLeft = isFirst ? rect.X + TextPadding : rect.X + DragHandleWidth;
int rightPad = ScrollbarVisible ? ScrollbarWidthHover + ScrollbarMargin * 2 : 0;
var textRect = new Rectangle(textLeft, rect.Y, rect.Right - XButtonSize - 6 - textLeft - rightPad, rect.Height);
using (var brush = new SolidBrush(TextColor))
using (var font = new Font("Segoe UI", isFirst ? 8.5f : 8f, isFirst ? FontStyle.Bold : FontStyle.Regular))
{
var sf = new StringFormat
{
Alignment = StringAlignment.Near,
LineAlignment = StringAlignment.Center,
Trimming = StringTrimming.EllipsisCharacter,
FormatFlags = StringFormatFlags.NoWrap
};
g.DrawString(_items[index], font, brush, textRect, sf);
}
}
private void DrawXButton(Graphics g, Rectangle itemRect, bool hovered)
{
var xRect = GetXButtonRect(itemRect);
using (var path = CreateRoundedRect(xRect, 3))
using (var brush = new SolidBrush(hovered ? XButtonHoverBg : XButtonBg))
g.FillPath(brush, path);
using (var pen = new Pen(Color.White, 1.4f) { StartCap = LineCap.Round, EndCap = LineCap.Round })
{
int p = 4;
g.DrawLine(pen, xRect.X + p, xRect.Y + p, xRect.Right - p, xRect.Bottom - p);
g.DrawLine(pen, xRect.Right - p, xRect.Y + p, xRect.X + p, xRect.Bottom - p);
}
}
private void DrawDropIndicator(Graphics g)
{
int y = (_dropIndex >= _items.Count ? _items.Count : _dropIndex) * (ItemHeight + ItemMargin) + ItemMargin / 2 - _scrollOffset;
int left = ItemMargin + 2;
int right = Width - ItemMargin - 2 - (ScrollbarVisible ? ScrollbarWidthHover + ScrollbarMargin : 0);
using (var pen = new Pen(AccentColor, 2.5f) { StartCap = LineCap.Round, EndCap = LineCap.Round })
g.DrawLine(pen, left, y, right, y);
}
// Draw custom scrollbar with hover expansion
private void DrawScrollbar(Graphics g)
{
if (MaxScroll <= 0) return;
bool expanded = _scrollbarHovered || _scrollbarDragging;
int sbWidth = expanded ? ScrollbarWidthHover : ScrollbarWidth;
int trackX = Width - ScrollbarWidth - ScrollbarMargin - (expanded ? (ScrollbarWidthHover - ScrollbarWidth) / 2 : 0);
_scrollTrackRect = new Rectangle(trackX, ScrollbarMargin, sbWidth, Height - ScrollbarMargin * 2);
using (var trackBrush = new SolidBrush(Color.FromArgb(40, ScrollTrackColor)))
using (var trackPath = CreateRoundedRect(_scrollTrackRect, ScrollbarRadius))
g.FillPath(trackBrush, trackPath);
// Calculate thumb position and size
int trackHeight = _scrollTrackRect.Height;
int thumbHeight = Math.Max(MinThumbHeight, (int)(trackHeight * ((float)Height / ContentHeight)));
float scrollRatio = MaxScroll > 0 ? (float)_scrollOffset / MaxScroll : 0;
int thumbY = ScrollbarMargin + (int)((trackHeight - thumbHeight) * scrollRatio);
_scrollThumbRect = new Rectangle(trackX, thumbY, sbWidth, thumbHeight);
Color thumbColor = _scrollbarDragging ? ScrollThumbDragColor : _scrollbarHovered ? ScrollThumbHoverColor : ScrollThumbColor;
using (var thumbBrush = new SolidBrush(thumbColor))
using (var thumbPath = CreateRoundedRect(_scrollThumbRect, ScrollbarRadius))
g.FillPath(thumbBrush, thumbPath);
}
private Rectangle GetItemRect(int index)
{
int y = index * (ItemHeight + ItemMargin) + ItemMargin - _scrollOffset;
int w = Width - ItemMargin * 2 - (ScrollbarVisible ? ScrollbarWidthHover + ScrollbarMargin + 2 : 0);
return new Rectangle(ItemMargin, y, w, ItemHeight);
}
private Rectangle GetXButtonRect(Rectangle itemRect) =>
new Rectangle(itemRect.Right - XButtonSize - 3, itemRect.Y + (itemRect.Height - XButtonSize) / 2, XButtonSize, XButtonSize);
private int HitTest(Point pt)
{
for (int i = 0; i < _items.Count; i++)
if (GetItemRect(i).Contains(pt)) return i;
return -1;
}
private bool HitTestScrollbar(Point pt) =>
ScrollbarVisible && new Rectangle(_scrollTrackRect.X - 4, _scrollTrackRect.Y, _scrollTrackRect.Width + 8, _scrollTrackRect.Height).Contains(pt);
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (_scrollbarDragging)
{
HandleScrollbarDrag(e.Y);
return;
}
// Update scrollbar hover state
bool wasHovered = _scrollbarHovered;
_scrollbarHovered = HitTestScrollbar(e.Location);
if (_scrollbarHovered != wasHovered) Invalidate();
if (_scrollbarHovered)
{
Cursor = Cursors.Default;
_hoveredIndex = -1;
_hoveringX = false;
return;
}
// Handle drag operation
if (_dragIndex >= 0)
{
UpdateAutoScroll(e.Y);
int newDrop = Math.Max(1, Math.Min(_items.Count, (e.Y + _scrollOffset + ItemHeight / 2) / (ItemHeight + ItemMargin)));
if (newDrop != _dropIndex) { _dropIndex = newDrop; Invalidate(); }
return;
}
// Update hover state
int hit = HitTest(e.Location);
bool overX = hit >= 0 && GetXButtonRect(GetItemRect(hit)).Contains(e.Location);
if (hit != _hoveredIndex || overX != _hoveringX)
{
_hoveredIndex = hit;
_hoveringX = overX;
Cursor = overX ? Cursors.Hand : hit > 0 ? Cursors.SizeNS : Cursors.Default;
Invalidate();
}
}
private void HandleScrollbarDrag(int mouseY)
{
int trackHeight = Height - ScrollbarMargin * 2;
int thumbHeight = Math.Max(MinThumbHeight, (int)(trackHeight * ((float)Height / ContentHeight)));
int scrollableHeight = trackHeight - thumbHeight;
if (scrollableHeight > 0)
{
float scrollRatio = (float)(mouseY - _scrollDragStartY) / scrollableHeight;
_scrollOffset = _scrollDragStartOffset + (int)(scrollRatio * MaxScroll);
ClampScroll();
Invalidate();
}
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button != MouseButtons.Left) return;
// Handle scrollbar thumb drag
if (ScrollbarVisible && _scrollThumbRect.Contains(e.Location))
{
_scrollbarDragging = true;
_scrollDragStartY = e.Y;
_scrollDragStartOffset = _scrollOffset;
Capture = true;
return;
}
// Handle scrollbar track click
if (ScrollbarVisible && HitTestScrollbar(e.Location))
{
_scrollOffset += e.Y < _scrollThumbRect.Top ? -Height : Height;
ClampScroll();
Invalidate();
return;
}
int hit = HitTest(e.Location);
if (hit < 0) return;
// Handle close button click
if (GetXButtonRect(GetItemRect(hit)).Contains(e.Location))
{
ItemRemoved?.Invoke(this, hit);
return;
}
// Start drag operation (only for non-first items)
if (hit > 0)
{
_dragIndex = _dropIndex = hit;
Capture = true;
Invalidate();
}
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
StopAutoScroll();
if (_scrollbarDragging)
{
_scrollbarDragging = false;
Capture = false;
Invalidate();
return;
}
// Complete drag reorder operation
if (_dragIndex > 0 && _dropIndex > 0 && _dropIndex != _dragIndex)
{
int from = _dragIndex;
int to = Math.Max(1, _dropIndex > _dragIndex ? _dropIndex - 1 : _dropIndex);
var item = _items[from];
_items.RemoveAt(from);
_items.Insert(to, item);
ItemReordered?.Invoke(this, new ReorderEventArgs(from, to));
}
_dragIndex = _dropIndex = -1;
Capture = false;
Cursor = Cursors.Default;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
if (_dragIndex < 0 && !_scrollbarDragging)
{
_hoveredIndex = -1;
_hoveringX = _scrollbarHovered = false;
Invalidate();
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
base.OnMouseWheel(e);
if (MaxScroll <= 0) return;
_scrollOffset -= e.Delta / 4;
ClampScroll();
Invalidate();
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
ClampScroll();
Invalidate();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_autoScrollTimer?.Stop();
_autoScrollTimer?.Dispose();
}
base.Dispose(disposing);
}
private static GraphicsPath CreateRoundedRect(Rectangle rect, int radius)
{
var path = new GraphicsPath();
if (radius <= 0 || rect.Width <= 0 || rect.Height <= 0)
{
path.AddRectangle(rect);
return path;
}
int d = Math.Min(radius * 2, Math.Min(rect.Width, rect.Height));
path.AddArc(rect.X, rect.Y, d, d, 180, 90);
path.AddArc(rect.Right - d, rect.Y, d, d, 270, 90);
path.AddArc(rect.Right - d, rect.Bottom - d, d, d, 0, 90);
path.AddArc(rect.X, rect.Bottom - d, d, d, 90, 90);
path.CloseFigure();
return path;
}
}
public class ReorderEventArgs : EventArgs
{
public int FromIndex { get; }
public int ToIndex { get; }
public ReorderEventArgs(int from, int to) { FromIndex = from; ToIndex = to; }
}
}

199
NewApps.Designer.cs generated
View File

@@ -1,199 +0,0 @@

namespace AndroidSideloader
{
partial class NewApps
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.NewAppsListView = new System.Windows.Forms.ListView();
this.GameNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.PackageNameIndex = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.panel1 = new System.Windows.Forms.Panel();
this.NewAppsButton = new AndroidSideloader.RoundButton();
this.label2 = new System.Windows.Forms.Label();
this.titleLabel = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
// NewAppsListView
//
this.NewAppsListView.AccessibleRole = System.Windows.Forms.AccessibleRole.None;
this.NewAppsListView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.NewAppsListView.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.NewAppsListView.CausesValidation = false;
this.NewAppsListView.CheckBoxes = true;
this.NewAppsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.GameNameIndex,
this.PackageNameIndex});
this.NewAppsListView.Dock = System.Windows.Forms.DockStyle.Fill;
this.NewAppsListView.Font = new System.Drawing.Font("Segoe UI", 9.5F);
this.NewAppsListView.ForeColor = System.Drawing.Color.White;
this.NewAppsListView.FullRowSelect = true;
this.NewAppsListView.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.NewAppsListView.HideSelection = false;
this.NewAppsListView.Location = new System.Drawing.Point(1, 1);
this.NewAppsListView.Name = "NewAppsListView";
this.NewAppsListView.Size = new System.Drawing.Size(298, 168);
this.NewAppsListView.TabIndex = 1;
this.NewAppsListView.UseCompatibleStateImageBehavior = false;
this.NewAppsListView.View = System.Windows.Forms.View.Details;
this.NewAppsListView.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
this.NewAppsListView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
this.NewAppsListView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
//
// GameNameIndex
//
this.GameNameIndex.Text = "App Name";
this.GameNameIndex.Width = 280;
//
// PackageNameIndex
//
this.PackageNameIndex.Width = 0;
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.panel1.Controls.Add(this.NewAppsButton);
this.panel1.Controls.Add(this.label2);
this.panel1.Controls.Add(this.titleLabel);
this.panel1.Controls.Add(this.panel2);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Padding = new System.Windows.Forms.Padding(16);
this.panel1.Size = new System.Drawing.Size(340, 300);
this.panel1.TabIndex = 10;
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
//
// NewAppsButton
//
this.NewAppsButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(140)))), ((int)(((byte)(115)))));
this.NewAppsButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(125)))), ((int)(((byte)(105)))));
this.NewAppsButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.NewAppsButton.BackColor = System.Drawing.Color.Transparent;
this.NewAppsButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.NewAppsButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.NewAppsButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.NewAppsButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.NewAppsButton.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold);
this.NewAppsButton.ForeColor = System.Drawing.Color.White;
this.NewAppsButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(120)))), ((int)(((byte)(100)))));
this.NewAppsButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(35)))), ((int)(((byte)(100)))), ((int)(((byte)(85)))));
this.NewAppsButton.Location = new System.Drawing.Point(20, 252);
this.NewAppsButton.Name = "NewAppsButton";
this.NewAppsButton.Radius = 4;
this.NewAppsButton.Size = new System.Drawing.Size(300, 36);
this.NewAppsButton.Stroke = true;
this.NewAppsButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(150)))), ((int)(((byte)(125)))));
this.NewAppsButton.TabIndex = 2;
this.NewAppsButton.Text = "Continue";
this.NewAppsButton.Transparency = false;
this.NewAppsButton.Click += new System.EventHandler(this.DonateButton_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.BackColor = System.Drawing.Color.Transparent;
this.label2.Font = new System.Drawing.Font("Segoe UI", 9F);
this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.label2.Location = new System.Drawing.Point(20, 42);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(223, 15);
this.label2.TabIndex = 9;
this.label2.Text = "Check the box for all free or non-VR apps";
this.label2.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
this.label2.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
this.label2.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
//
// titleLabel
//
this.titleLabel.AutoSize = true;
this.titleLabel.BackColor = System.Drawing.Color.Transparent;
this.titleLabel.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.titleLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.titleLabel.Location = new System.Drawing.Point(20, 15);
this.titleLabel.Name = "titleLabel";
this.titleLabel.Size = new System.Drawing.Size(129, 20);
this.titleLabel.TabIndex = 11;
this.titleLabel.Text = "New Apps Found";
this.titleLabel.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
this.titleLabel.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
this.titleLabel.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
//
// panel2
//
this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.panel2.Controls.Add(this.NewAppsListView);
this.panel2.Location = new System.Drawing.Point(20, 70);
this.panel2.Name = "panel2";
this.panel2.Padding = new System.Windows.Forms.Padding(1);
this.panel2.Size = new System.Drawing.Size(300, 170);
this.panel2.TabIndex = 8;
//
// NewApps
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.ClientSize = new System.Drawing.Size(340, 300);
this.ControlBox = false;
this.Controls.Add(this.panel1);
this.ForeColor = System.Drawing.Color.White;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "NewApps";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Load += new System.EventHandler(this.NewApps_Load);
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.label2_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.label2_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.label2_MouseUp);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListView NewAppsListView;
private System.Windows.Forms.ColumnHeader GameNameIndex;
private System.Windows.Forms.Panel panel1;
private System.Windows.Forms.Panel panel2;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.Label titleLabel;
private System.Windows.Forms.ColumnHeader PackageNameIndex;
private RoundButton NewAppsButton;
}
}

View File

@@ -1,203 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class NewApps : Form
{
// Modern theme colors
private static readonly Color BackgroundColor = Color.FromArgb(20, 24, 29);
private static readonly Color BorderColor = Color.FromArgb(70, 80, 100);
// Shadow and corner settings
private const int CS_DROPSHADOW = 0x00020000;
private const int WM_NCLBUTTONDOWN = 0xA1;
private const int HT_CAPTION = 0x2;
private const int SHADOW_SIZE = 2;
private const int CONTENT_RADIUS = 10;
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
private static extern bool ReleaseCapture();
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ClassStyle |= CS_DROPSHADOW;
return cp;
}
}
public NewApps()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
ApplyModernTheme();
CenterToScreen();
}
private void ApplyModernTheme()
{
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.FromArgb(25, 25, 30);
this.Padding = new Padding(5);
panel1.BackColor = BackgroundColor;
panel1.Location = new Point(6, 6);
panel1.Size = new Size(this.ClientSize.Width - 12, this.ClientSize.Height - 12);
panel1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
this.Paint += Form_Paint;
// Close button
var closeButton = new Button
{
Text = "✕",
Font = new Font("Segoe UI", 9F),
ForeColor = Color.White,
BackColor = BackgroundColor,
FlatStyle = FlatStyle.Flat,
Size = new Size(30, 28),
Location = new Point(panel1.Width - 35, 5),
Cursor = Cursors.Hand,
TabStop = false
};
closeButton.FlatAppearance.BorderSize = 0;
closeButton.FlatAppearance.MouseOverBackColor = Color.FromArgb(200, 60, 60);
closeButton.Click += (s, e) => Close();
panel1.Controls.Add(closeButton);
closeButton.BringToFront();
// Enable dragging
panel1.MouseDown += TitleArea_MouseDown;
label2.MouseDown += TitleArea_MouseDown;
titleLabel.MouseDown += TitleArea_MouseDown;
}
private void TitleArea_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ReleaseCapture();
SendMessage(this.Handle, WM_NCLBUTTONDOWN, (IntPtr)HT_CAPTION, IntPtr.Zero);
}
}
private void Form_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int w = this.Width;
int h = this.Height;
// Draw shadow layers
for (int i = SHADOW_SIZE; i >= 1; i--)
{
int alpha = (SHADOW_SIZE - i + 1) * 12;
Rectangle shadowRect = new Rectangle(
SHADOW_SIZE - i,
SHADOW_SIZE - i,
w - (SHADOW_SIZE - i) * 2 - 1,
h - (SHADOW_SIZE - i) * 2 - 1);
using (Pen shadowPen = new Pen(Color.FromArgb(alpha, 0, 0, 0), 1))
using (GraphicsPath shadowPath = CreateRoundedRectPath(shadowRect, CONTENT_RADIUS + i))
{
e.Graphics.DrawPath(shadowPen, shadowPath);
}
}
// Draw content background
Rectangle contentRect = new Rectangle(SHADOW_SIZE, SHADOW_SIZE, w - SHADOW_SIZE * 2, h - SHADOW_SIZE * 2);
using (GraphicsPath contentPath = CreateRoundedRectPath(contentRect, CONTENT_RADIUS))
{
using (SolidBrush bgBrush = new SolidBrush(BackgroundColor))
{
e.Graphics.FillPath(bgBrush, contentPath);
}
using (Pen borderPen = new Pen(BorderColor, 1f))
{
e.Graphics.DrawPath(borderPen, contentPath);
}
}
// Apply rounded region
using (GraphicsPath regionPath = CreateRoundedRectPath(new Rectangle(0, 0, w, h), CONTENT_RADIUS + SHADOW_SIZE))
{
this.Region = new Region(regionPath);
}
}
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
{
GraphicsPath path = new GraphicsPath();
if (radius <= 0)
{
path.AddRectangle(rect);
return path;
}
int diameter = Math.Min(radius * 2, Math.Min(rect.Width, rect.Height));
radius = diameter / 2;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
path.AddArc(arcRect, 180, 90);
arcRect.X = rect.Right - diameter;
path.AddArc(arcRect, 270, 90);
arcRect.Y = rect.Bottom - diameter;
path.AddArc(arcRect, 0, 90);
arcRect.X = rect.Left;
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
private void label2_MouseDown(object sender, MouseEventArgs e) => TitleArea_MouseDown(sender, e);
private void label2_MouseMove(object sender, MouseEventArgs e) { }
private void label2_MouseUp(object sender, MouseEventArgs e) { }
private void DonateButton_Click(object sender, EventArgs e)
{
string HWID = SideloaderUtilities.UUID();
foreach (ListViewItem listItem in NewAppsListView.Items)
{
if (listItem.Checked)
Properties.Settings.Default.NonAppPackages += listItem.SubItems[Donors.PackageNameIndex].Text + ";" + HWID + "\n";
else
Properties.Settings.Default.AppPackages += listItem.SubItems[Donors.PackageNameIndex].Text + "\n";
Properties.Settings.Default.Save();
}
MainForm.newPackageUpload();
Close();
}
private void NewApps_Load(object sender, EventArgs e)
{
NewAppsListView.Items.Clear();
Donors.initNewApps();
var NewAppList = new List<ListViewItem>();
foreach (string[] release in Donors.newApps)
{
ListViewItem NGame = new ListViewItem(release);
if (!NewAppList.Contains(NGame))
NewAppList.Add(NGame);
}
NewAppsListView.BeginUpdate();
NewAppsListView.Items.AddRange(NewAppList.ToArray());
NewAppsListView.EndUpdate();
}
}
}

View File

@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1,110 +1,34 @@
using AndroidSideloader.Utilities;
using System;
using System.IO;
using System.Security.Permissions;
using System.Windows.Forms;
namespace AndroidSideloader
{
internal static class Program
{
private static SettingsManager settings;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
private static void Main()
{
// Handle corrupted user.config files
bool configFixed = false;
Exception configException = null;
try
{
// Force settings initialization to trigger any config errors early
var test = AndroidSideloader.Properties.Settings.Default.FontStyle;
}
catch (Exception ex)
{
configException = ex;
// Delete the corrupted config file and retry
try
{
string configPath = GetUserConfigPath();
if (!string.IsNullOrEmpty(configPath) && File.Exists(configPath))
{
File.Delete(configPath);
configFixed = true;
}
}
catch
{
// If we can't delete it, try to continue anyway
}
}
if (configFixed)
{
// Restart the application after fixing config
Application.Restart();
return;
}
if (configException != null)
{
MessageBox.Show(
"Settings file is corrupted and could not be repaired automatically.\n\n" +
"Please delete this folder and restart the application:\n" +
Path.GetDirectoryName(GetUserConfigPath()),
"Configuration Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}
settings = SettingsManager.Instance;
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(CrashHandler);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new MainForm();
Application.Run(form);
//form.Show();
}
private static string GetUserConfigPath()
{
try
{
string appData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
string companyName = "Rookie.AndroidSideloader";
string exeName = "AndroidSideloader.exe_Url_dkp0unsd4fjaabhwwafgfxvvbrerf10b";
string version = "2.0.0.0";
return Path.Combine(appData, companyName, exeName, version, "user.config");
}
catch
{
return null;
}
}
public static MainForm form;
private static void CrashHandler(object sender, UnhandledExceptionEventArgs args)
{
// Capture unhandled exceptions and write to file.
Exception e = (Exception)args.ExceptionObject;
string innerExceptionMessage = (e.InnerException != null)
? e.InnerException.Message
: "None";
string date_time = DateTime.Now.ToString("dddd, MMMM dd @ hh:mmtt (UTC)");
File.WriteAllText(Sideloader.CrashLogPath, $"Date/Time of crash: {date_time}\nMessage: {e.Message}\nInner Message: {innerExceptionMessage}\nData: {e.Data}\nSource: {e.Source}\nTargetSite: {e.TargetSite}\nStack Trace: \n{e.StackTrace}\n\n\nDebuglog: \n\n\n");
// If a debuglog exists we append it to the crashlog.
if (settings != null && File.Exists(settings.CurrentLogPath))
{
File.AppendAllText(Sideloader.CrashLogPath, File.ReadAllText($"{settings.CurrentLogPath}"));
}
}
}
}
using System;
using System.Windows.Forms;
using System.Security.Permissions;
using System.IO;
namespace AndroidSideloader
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new MainForm();
Application.Run(form);
//form.Show();
}
public static MainForm form;
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
File.WriteAllText(Sideloader.CrashLogPath, $"Message: {e.Message}\nData: {e.Data}\nSource: {e.Source}\nTargetSite: {e.TargetSite}");
}
}
}

View File

@@ -1,4 +1,5 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -6,9 +7,9 @@ using System.Runtime.InteropServices;
// associated with an assembly.
//[assembly: AssemblyKeyFileAttribute("keypair.snk")]
[assembly: AssemblyTitle("AndroidSideloader")]
[assembly: AssemblyDescription("Rookie Sideloader")]
[assembly: AssemblyDescription("Rookie's Sideloader")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Rookie.AndroidSideloader")]
[assembly: AssemblyCompany("Rookie.WTF")]
[assembly: AssemblyProduct("AndroidSideloader")]
[assembly: AssemblyCopyright("Copyright © 2020")]
[assembly: AssemblyTrademark("")]

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is automatically generated by Visual Studio .Net. It is
used to store generic object data source configuration information.
Renaming the file extension or editing the content of this file may
cause the file to be unrecognizable by the program.
-->
<GenericObjectDataSource DisplayName="Resources" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<TypeInfo>AndroidSideloader.Properties.Resources, Properties.Resources.Designer.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
</GenericObjectDataSource>

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is automatically generated by Visual Studio .Net. It is
used to store generic object data source configuration information.
Renaming the file extension or editing the content of this file may
cause the file to be unrecognizable by the program.
-->
<GenericObjectDataSource DisplayName="Settings" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<TypeInfo>AndroidSideloader.Properties.Settings, Properties.Resources.Designer.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
</GenericObjectDataSource>

View File

@@ -19,7 +19,7 @@ namespace AndroidSideloader.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resources {
@@ -59,35 +59,5 @@ namespace AndroidSideloader.Properties {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
public static System.Drawing.Bitmap ajax_loader {
get {
object obj = ResourceManager.GetObject("ajax-loader", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
public static System.Drawing.Bitmap battery {
get {
object obj = ResourceManager.GetObject("battery", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
public static System.Drawing.Bitmap SearchGlass {
get {
object obj = ResourceManager.GetObject("SearchGlass", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@@ -117,14 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="battery" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\battery.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ajax-loader" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ajax-loader.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SearchGlass" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\SearchGlass.PNG;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@@ -1,745 +1,254 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AndroidSideloader.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.14.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool checkForUpdates {
get {
return ((bool)(this["checkForUpdates"]));
}
set {
this["checkForUpdates"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool enableMessageBoxes {
get {
return ((bool)(this["enableMessageBoxes"]));
}
set {
this["enableMessageBoxes"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool firstRun {
get {
return ((bool)(this["firstRun"]));
}
set {
this["firstRun"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool deleteAllAfterInstall {
get {
return ((bool)(this["deleteAllAfterInstall"]));
}
set {
this["deleteAllAfterInstall"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool autoUpdateConfig {
get {
return ((bool)(this["autoUpdateConfig"]));
}
set {
this["autoUpdateConfig"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool userJsonOnGameInstall {
get {
return ((bool)(this["userJsonOnGameInstall"]));
}
set {
this["userJsonOnGameInstall"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool CallUpgrade {
get {
return ((bool)(this["CallUpgrade"]));
}
set {
this["CallUpgrade"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Microsoft Sans Serif, 10pt")]
public global::System.Drawing.Font FontStyle {
get {
return ((global::System.Drawing.Font)(this["FontStyle"]));
}
set {
this["FontStyle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string BackPicturePath {
get {
return ((string)(this["BackPicturePath"]));
}
set {
this["BackPicturePath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool SpoofGames {
get {
return ((bool)(this["SpoofGames"]));
}
set {
this["SpoofGames"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Microsoft Sans Serif, 14pt")]
public global::System.Drawing.Font BigFontStyle {
get {
return ((global::System.Drawing.Font)(this["BigFontStyle"]));
}
set {
this["BigFontStyle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool ResignAPKs {
get {
return ((bool)(this["ResignAPKs"]));
}
set {
this["ResignAPKs"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string IPAddress {
get {
return ((string)(this["IPAddress"]));
}
set {
this["IPAddress"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string InstalledApps {
get {
return ((string)(this["InstalledApps"]));
}
set {
this["InstalledApps"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string ADBPath {
get {
return ((string)(this["ADBPath"]));
}
set {
this["ADBPath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string MainDir {
get {
return ((string)(this["MainDir"]));
}
set {
this["MainDir"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool delsh {
get {
return ((bool)(this["delsh"]));
}
set {
this["delsh"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string CurrPckg {
get {
return ((string)(this["CurrPckg"]));
}
set {
this["CurrPckg"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string ADBFolder {
get {
return ((string)(this["ADBFolder"]));
}
set {
this["ADBFolder"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool WirelessADB {
get {
return ((bool)(this["WirelessADB"]));
}
set {
this["WirelessADB"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string CurrentGamename {
get {
return ((string)(this["CurrentGamename"]));
}
set {
this["CurrentGamename"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool PackageNameToCB {
get {
return ((bool)(this["PackageNameToCB"]));
}
set {
this["PackageNameToCB"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool DownUpHeld {
get {
return ((bool)(this["DownUpHeld"]));
}
set {
this["DownUpHeld"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string CurrentLogPath {
get {
return ((string)(this["CurrentLogPath"]));
}
set {
this["CurrentLogPath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string CurrentLogName {
get {
return ((string)(this["CurrentLogName"]));
}
set {
this["CurrentLogName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string CurrentCrashPath {
get {
return ((string)(this["CurrentCrashPath"]));
}
set {
this["CurrentCrashPath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string CurrentCrashName {
get {
return ((string)(this["CurrentCrashName"]));
}
set {
this["CurrentCrashName"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool adbdebugwarned {
get {
return ((bool)(this["adbdebugwarned"]));
}
set {
this["adbdebugwarned"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool nodevicemode {
get {
return ((bool)(this["nodevicemode"]));
}
set {
this["nodevicemode"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool BMBFchecked {
get {
return ((bool)(this["BMBFchecked"]));
}
set {
this["BMBFchecked"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string GamesList {
get {
return ((string)(this["GamesList"]));
}
set {
this["GamesList"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool UploadedGameList {
get {
return ((bool)(this["UploadedGameList"]));
}
set {
this["UploadedGameList"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string GlobalUsername {
get {
return ((string)(this["GlobalUsername"]));
}
set {
this["GlobalUsername"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.DateTime lastTimeShared {
get {
return ((global::System.DateTime)(this["lastTimeShared"]));
}
set {
this["lastTimeShared"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool AutoReinstall {
get {
return ((bool)(this["AutoReinstall"]));
}
set {
this["AutoReinstall"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string NonAppPackages {
get {
return ((string)(this["NonAppPackages"]));
}
set {
this["NonAppPackages"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("04/20/1969 16:20:00")]
public global::System.DateTime LastLaunch {
get {
return ((global::System.DateTime)(this["LastLaunch"]));
}
set {
this["LastLaunch"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string SubmittedUpdates {
get {
return ((string)(this["SubmittedUpdates"]));
}
set {
this["SubmittedUpdates"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool ListUpped {
get {
return ((bool)(this["ListUpped"]));
}
set {
this["ListUpped"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("04/20/1969 16:20:00")]
public global::System.DateTime LastLaunch2 {
get {
return ((global::System.DateTime)(this["LastLaunch2"]));
}
set {
this["LastLaunch2"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool Wired {
get {
return ((bool)(this["Wired"]));
}
set {
this["Wired"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("White")]
public global::System.Drawing.Color FontColor {
get {
return ((global::System.Drawing.Color)(this["FontColor"]));
}
set {
this["FontColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("25, 25, 25")]
public global::System.Drawing.Color ComboBoxColor {
get {
return ((global::System.Drawing.Color)(this["ComboBoxColor"]));
}
set {
this["ComboBoxColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("42, 45, 58")]
public global::System.Drawing.Color SubButtonColor {
get {
return ((global::System.Drawing.Color)(this["SubButtonColor"]));
}
set {
this["SubButtonColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("25, 25, 25")]
public global::System.Drawing.Color TextBoxColor {
get {
return ((global::System.Drawing.Color)(this["TextBoxColor"]));
}
set {
this["TextBoxColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("32, 35, 45")]
public global::System.Drawing.Color ButtonColor {
get {
return ((global::System.Drawing.Color)(this["ButtonColor"]));
}
set {
this["ButtonColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("31, 34, 42")]
public global::System.Drawing.Color BackColor {
get {
return ((global::System.Drawing.Color)(this["BackColor"]));
}
set {
this["BackColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string AppPackages {
get {
return ((string)(this["AppPackages"]));
}
set {
this["AppPackages"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool TrailersOn {
get {
return ((bool)(this["TrailersOn"]));
}
set {
this["TrailersOn"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string downloadDir {
get {
return ((string)(this["downloadDir"]));
}
set {
this["downloadDir"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool customDownloadDir {
get {
return ((bool)(this["customDownloadDir"]));
}
set {
this["customDownloadDir"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool customBackupDir {
get {
return ((bool)(this["customBackupDir"]));
}
set {
this["customBackupDir"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string backupDir {
get {
return ((string)(this["backupDir"]));
}
set {
this["backupDir"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool singleThreadMode {
get {
return ((bool)(this["singleThreadMode"]));
}
set {
this["singleThreadMode"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool virtualFilesystemCompatibility {
get {
return ((bool)(this["virtualFilesystemCompatibility"]));
}
set {
this["virtualFilesystemCompatibility"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool UpdateSettings {
get {
return ((bool)(this["UpdateSettings"]));
}
set {
this["UpdateSettings"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string UUID {
get {
return ((string)(this["UUID"]));
}
set {
this["UUID"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool createPubMirrorFile {
get {
return ((bool)(this["createPubMirrorFile"]));
}
set {
this["createPubMirrorFile"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool useDownloadedFiles {
get {
return ((bool)(this["useDownloadedFiles"]));
}
set {
this["useDownloadedFiles"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("0")]
public float bandwidthLimit {
get {
return ((float)(this["bandwidthLimit"]));
}
set {
this["bandwidthLimit"] = value;
}
}
}
}
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace AndroidSideloader.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool checkForUpdates {
get {
return ((bool)(this["checkForUpdates"]));
}
set {
this["checkForUpdates"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool enableMessageBoxes {
get {
return ((bool)(this["enableMessageBoxes"]));
}
set {
this["enableMessageBoxes"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool firstRun {
get {
return ((bool)(this["firstRun"]));
}
set {
this["firstRun"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool deleteAllAfterInstall {
get {
return ((bool)(this["deleteAllAfterInstall"]));
}
set {
this["deleteAllAfterInstall"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool autoUpdateConfig {
get {
return ((bool)(this["autoUpdateConfig"]));
}
set {
this["autoUpdateConfig"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool userJsonOnGameInstall {
get {
return ((bool)(this["userJsonOnGameInstall"]));
}
set {
this["userJsonOnGameInstall"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool CallUpgrade {
get {
return ((bool)(this["CallUpgrade"]));
}
set {
this["CallUpgrade"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("45, 45, 45")]
public global::System.Drawing.Color BackColor {
get {
return ((global::System.Drawing.Color)(this["BackColor"]));
}
set {
this["BackColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("ActiveCaptionText")]
public global::System.Drawing.Color ButtonColor {
get {
return ((global::System.Drawing.Color)(this["ButtonColor"]));
}
set {
this["ButtonColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("64, 64, 64")]
public global::System.Drawing.Color SubButtonColor {
get {
return ((global::System.Drawing.Color)(this["SubButtonColor"]));
}
set {
this["SubButtonColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("45, 45, 45")]
public global::System.Drawing.Color TextBoxColor {
get {
return ((global::System.Drawing.Color)(this["TextBoxColor"]));
}
set {
this["TextBoxColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("45, 45, 45")]
public global::System.Drawing.Color ComboBoxColor {
get {
return ((global::System.Drawing.Color)(this["ComboBoxColor"]));
}
set {
this["ComboBoxColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("White")]
public global::System.Drawing.Color FontColor {
get {
return ((global::System.Drawing.Color)(this["FontColor"]));
}
set {
this["FontColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Microsoft Sans Serif, 11.25pt")]
public global::System.Drawing.Font FontStyle {
get {
return ((global::System.Drawing.Font)(this["FontStyle"]));
}
set {
this["FontStyle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string BackPicturePath {
get {
return ((string)(this["BackPicturePath"]));
}
set {
this["BackPicturePath"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool SpoofGames {
get {
return ((bool)(this["SpoofGames"]));
}
set {
this["SpoofGames"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string BandwithLimit {
get {
return ((string)(this["BandwithLimit"]));
}
set {
this["BandwithLimit"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Microsoft Sans Serif, 16pt")]
public global::System.Drawing.Font BigFontStyle {
get {
return ((global::System.Drawing.Font)(this["BigFontStyle"]));
}
set {
this["BigFontStyle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("False")]
public bool ResignAPKs {
get {
return ((bool)(this["ResignAPKs"]));
}
set {
this["ResignAPKs"] = value;
}
}
}
}

View File

@@ -18,13 +18,31 @@
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="userJsonOnGameInstall" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="CallUpgrade" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="BackColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">45, 45, 45</Value>
</Setting>
<Setting Name="ButtonColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">ActiveCaptionText</Value>
</Setting>
<Setting Name="SubButtonColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">64, 64, 64</Value>
</Setting>
<Setting Name="TextBoxColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">45, 45, 45</Value>
</Setting>
<Setting Name="ComboBoxColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">45, 45, 45</Value>
</Setting>
<Setting Name="FontColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">White</Value>
</Setting>
<Setting Name="FontStyle" Type="System.Drawing.Font" Scope="User">
<Value Profile="(Default)">Microsoft Sans Serif, 10pt</Value>
<Value Profile="(Default)">Microsoft Sans Serif, 11.25pt</Value>
</Setting>
<Setting Name="BackPicturePath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
@@ -32,167 +50,14 @@
<Setting Name="SpoofGames" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="BandwithLimit" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="BigFontStyle" Type="System.Drawing.Font" Scope="User">
<Value Profile="(Default)">Microsoft Sans Serif, 14pt</Value>
<Value Profile="(Default)">Microsoft Sans Serif, 16pt</Value>
</Setting>
<Setting Name="ResignAPKs" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="IPAddress" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="InstalledApps" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="ADBPath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="MainDir" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="delsh" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="CurrPckg" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="ADBFolder" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="WirelessADB" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="CurrentGamename" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="PackageNameToCB" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="DownUpHeld" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="CurrentLogPath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="CurrentLogName" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="CurrentCrashPath" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="CurrentCrashName" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="adbdebugwarned" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="nodevicemode" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="BMBFchecked" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="GamesList" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="UploadedGameList" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="GlobalUsername" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="lastTimeShared" Type="System.DateTime" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="AutoReinstall" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="NonAppPackages" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="LastLaunch" Type="System.DateTime" Scope="User">
<Value Profile="(Default)">04/20/1969 16:20:00</Value>
</Setting>
<Setting Name="SubmittedUpdates" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="ListUpped" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="LastLaunch2" Type="System.DateTime" Scope="User">
<Value Profile="(Default)">04/20/1969 16:20:00</Value>
</Setting>
<Setting Name="Wired" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="FontColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">White</Value>
</Setting>
<Setting Name="ComboBoxColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">25, 25, 25</Value>
</Setting>
<Setting Name="SubButtonColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">42, 45, 58</Value>
</Setting>
<Setting Name="TextBoxColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">25, 25, 25</Value>
</Setting>
<Setting Name="ButtonColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">32, 35, 45</Value>
</Setting>
<Setting Name="BackColor" Type="System.Drawing.Color" Scope="User">
<Value Profile="(Default)">31, 34, 42</Value>
</Setting>
<Setting Name="AppPackages" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="TrailersOn" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="downloadDir" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="customDownloadDir" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="customBackupDir" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="backupDir" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="singleThreadMode" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="virtualFilesystemCompatibility" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="UpdateSettings" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="UUID" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="createPubMirrorFile" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="useDownloadedFiles" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="bandwidthLimit" Type="System.Single" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="useProxy" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="proxyAddress" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="proxyPort" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="selectedMirror" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
</Settings>
</SettingsFile>

671
QuestForm.Designer.cs generated
View File

@@ -1,496 +1,177 @@
using System.Windows.Forms;
namespace AndroidSideloader
{
partial class QuestForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lblUsernameSection = new System.Windows.Forms.Label();
this.lblMediaSection = new System.Windows.Forms.Label();
this.lblPerformanceSection = new System.Windows.Forms.Label();
this.GlobalUsername = new System.Windows.Forms.TextBox();
this.btnApplyUsername = new AndroidSideloader.RoundButton();
this.questPics = new AndroidSideloader.RoundButton();
this.questVids = new AndroidSideloader.RoundButton();
this.lblScreenshotsPath = new System.Windows.Forms.Label();
this.lblRecordingsPath = new System.Windows.Forms.Label();
this.toggleDeleteAfterTransfer = new AndroidSideloader.ToggleSwitch();
this.lblDeleteAfterTransfer = new System.Windows.Forms.Label();
this.lblPerformanceNote = new System.Windows.Forms.Label();
this.lblRefreshRate = new System.Windows.Forms.Label();
this.RefreshRateComboBox = new System.Windows.Forms.ComboBox();
this.lblGpuLevel = new System.Windows.Forms.Label();
this.GPUComboBox = new System.Windows.Forms.ComboBox();
this.lblCpuLevel = new System.Windows.Forms.Label();
this.CPUComboBox = new System.Windows.Forms.ComboBox();
this.lblResolution = new System.Windows.Forms.Label();
this.TextureResTextBox = new System.Windows.Forms.TextBox();
this.btnApplyTempSettings = new AndroidSideloader.RoundButton();
this.separator1 = new System.Windows.Forms.Panel();
this.separator2 = new System.Windows.Forms.Panel();
this.btnClose = new AndroidSideloader.RoundButton();
this.SuspendLayout();
//
// lblUsernameSection
//
this.lblUsernameSection.AutoSize = true;
this.lblUsernameSection.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.lblUsernameSection.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.lblUsernameSection.Location = new System.Drawing.Point(20, 15);
this.lblUsernameSection.Name = "lblUsernameSection";
this.lblUsernameSection.Size = new System.Drawing.Size(80, 20);
this.lblUsernameSection.TabIndex = 0;
this.lblUsernameSection.Text = "Username";
//
// lblMediaSection
//
this.lblMediaSection.AutoSize = true;
this.lblMediaSection.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.lblMediaSection.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.lblMediaSection.Location = new System.Drawing.Point(20, 97);
this.lblMediaSection.Name = "lblMediaSection";
this.lblMediaSection.Size = new System.Drawing.Size(114, 20);
this.lblMediaSection.TabIndex = 3;
this.lblMediaSection.Text = "Media Transfer";
//
// lblPerformanceSection
//
this.lblPerformanceSection.AutoSize = true;
this.lblPerformanceSection.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
this.lblPerformanceSection.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.lblPerformanceSection.Location = new System.Drawing.Point(20, 232);
this.lblPerformanceSection.Name = "lblPerformanceSection";
this.lblPerformanceSection.Size = new System.Drawing.Size(147, 20);
this.lblPerformanceSection.TabIndex = 9;
this.lblPerformanceSection.Text = "Temporary Settings";
//
// GlobalUsername
//
this.GlobalUsername.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.GlobalUsername.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.GlobalUsername.Font = new System.Drawing.Font("Segoe UI", 9.5F);
this.GlobalUsername.ForeColor = System.Drawing.Color.White;
this.GlobalUsername.Location = new System.Drawing.Point(24, 45);
this.GlobalUsername.Name = "GlobalUsername";
this.GlobalUsername.Size = new System.Drawing.Size(200, 24);
this.GlobalUsername.TabIndex = 1;
this.GlobalUsername.TextChanged += new System.EventHandler(this.GlobalUsername_TextChanged);
//
// btnApplyUsername
//
this.btnApplyUsername.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(113)))), ((int)(((byte)(223)))), ((int)(((byte)(193)))));
this.btnApplyUsername.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(113)))), ((int)(((byte)(223)))), ((int)(((byte)(193)))));
this.btnApplyUsername.BackColor = System.Drawing.Color.Transparent;
this.btnApplyUsername.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnApplyUsername.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnApplyUsername.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.btnApplyUsername.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.btnApplyUsername.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.btnApplyUsername.Enabled = false;
this.btnApplyUsername.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.btnApplyUsername.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(80)))), ((int)(((byte)(80)))), ((int)(((byte)(80)))));
this.btnApplyUsername.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.btnApplyUsername.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.btnApplyUsername.Location = new System.Drawing.Point(234, 45);
this.btnApplyUsername.Name = "btnApplyUsername";
this.btnApplyUsername.Radius = 5;
this.btnApplyUsername.Size = new System.Drawing.Size(80, 25);
this.btnApplyUsername.Stroke = false;
this.btnApplyUsername.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.btnApplyUsername.TabIndex = 1;
this.btnApplyUsername.Text = "APPLY";
this.btnApplyUsername.Transparency = false;
this.btnApplyUsername.Click += new System.EventHandler(this.btnApplyUsername_Click);
//
// questPics
//
this.questPics.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.questPics.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.questPics.BackColor = System.Drawing.Color.Transparent;
this.questPics.Cursor = System.Windows.Forms.Cursors.Hand;
this.questPics.DialogResult = System.Windows.Forms.DialogResult.OK;
this.questPics.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.questPics.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.questPics.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.questPics.Font = new System.Drawing.Font("Segoe UI", 9F);
this.questPics.ForeColor = System.Drawing.Color.White;
this.questPics.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.questPics.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.questPics.Location = new System.Drawing.Point(24, 127);
this.questPics.Name = "questPics";
this.questPics.Radius = 5;
this.questPics.Size = new System.Drawing.Size(140, 28);
this.questPics.Stroke = true;
this.questPics.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(65)))), ((int)(((byte)(75)))));
this.questPics.TabIndex = 2;
this.questPics.Text = "Screenshots";
this.questPics.Transparency = false;
this.questPics.Click += new System.EventHandler(this.questPics_Click);
//
// questVids
//
this.questVids.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.questVids.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.questVids.BackColor = System.Drawing.Color.Transparent;
this.questVids.Cursor = System.Windows.Forms.Cursors.Hand;
this.questVids.DialogResult = System.Windows.Forms.DialogResult.OK;
this.questVids.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.questVids.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.questVids.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.questVids.Font = new System.Drawing.Font("Segoe UI", 9F);
this.questVids.ForeColor = System.Drawing.Color.White;
this.questVids.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.questVids.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.questVids.Location = new System.Drawing.Point(174, 127);
this.questVids.Name = "questVids";
this.questVids.Radius = 5;
this.questVids.Size = new System.Drawing.Size(140, 28);
this.questVids.Stroke = true;
this.questVids.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(65)))), ((int)(((byte)(75)))));
this.questVids.TabIndex = 3;
this.questVids.Text = "Recordings";
this.questVids.Transparency = false;
this.questVids.Click += new System.EventHandler(this.questVids_Click);
//
// lblScreenshotsPath
//
this.lblScreenshotsPath.AutoSize = true;
this.lblScreenshotsPath.Font = new System.Drawing.Font("Segoe UI", 8F);
this.lblScreenshotsPath.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.lblScreenshotsPath.Location = new System.Drawing.Point(24, 158);
this.lblScreenshotsPath.Name = "lblScreenshotsPath";
this.lblScreenshotsPath.Size = new System.Drawing.Size(161, 13);
this.lblScreenshotsPath.TabIndex = 4;
this.lblScreenshotsPath.Text = "→ Desktop\\Quest Screenshots";
//
// lblRecordingsPath
//
this.lblRecordingsPath.AutoSize = true;
this.lblRecordingsPath.Font = new System.Drawing.Font("Segoe UI", 8F);
this.lblRecordingsPath.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.lblRecordingsPath.Location = new System.Drawing.Point(174, 158);
this.lblRecordingsPath.Name = "lblRecordingsPath";
this.lblRecordingsPath.Size = new System.Drawing.Size(157, 13);
this.lblRecordingsPath.TabIndex = 5;
this.lblRecordingsPath.Text = "→ Desktop\\Quest Recordings";
//
// toggleDeleteAfterTransfer
//
this.toggleDeleteAfterTransfer.BackColor = System.Drawing.Color.Transparent;
this.toggleDeleteAfterTransfer.Cursor = System.Windows.Forms.Cursors.Hand;
this.toggleDeleteAfterTransfer.Location = new System.Drawing.Point(27, 189);
this.toggleDeleteAfterTransfer.Name = "toggleDeleteAfterTransfer";
this.toggleDeleteAfterTransfer.OffColor = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(65)))), ((int)(((byte)(75)))));
this.toggleDeleteAfterTransfer.OnColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.toggleDeleteAfterTransfer.Size = new System.Drawing.Size(36, 18);
this.toggleDeleteAfterTransfer.TabIndex = 6;
this.toggleDeleteAfterTransfer.ThumbColor = System.Drawing.Color.White;
this.toggleDeleteAfterTransfer.CheckedChanged += new System.EventHandler(this.toggleDeleteAfterTransfer_CheckedChanged);
//
// lblDeleteAfterTransfer
//
this.lblDeleteAfterTransfer.AutoSize = true;
this.lblDeleteAfterTransfer.Font = new System.Drawing.Font("Segoe UI", 9.5F);
this.lblDeleteAfterTransfer.ForeColor = System.Drawing.Color.White;
this.lblDeleteAfterTransfer.Location = new System.Drawing.Point(72, 188);
this.lblDeleteAfterTransfer.Name = "lblDeleteAfterTransfer";
this.lblDeleteAfterTransfer.Size = new System.Drawing.Size(195, 17);
this.lblDeleteAfterTransfer.TabIndex = 7;
this.lblDeleteAfterTransfer.Text = "Delete from Quest after transfer";
//
// lblPerformanceNote
//
this.lblPerformanceNote.AutoSize = true;
this.lblPerformanceNote.Font = new System.Drawing.Font("Segoe UI", 8F);
this.lblPerformanceNote.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(120)))), ((int)(((byte)(120)))));
this.lblPerformanceNote.Location = new System.Drawing.Point(21, 254);
this.lblPerformanceNote.Name = "lblPerformanceNote";
this.lblPerformanceNote.Size = new System.Drawing.Size(120, 13);
this.lblPerformanceNote.TabIndex = 10;
this.lblPerformanceNote.Text = "Reboot Quest to reset";
//
// lblRefreshRate
//
this.lblRefreshRate.AutoSize = true;
this.lblRefreshRate.Font = new System.Drawing.Font("Segoe UI", 9F);
this.lblRefreshRate.ForeColor = System.Drawing.Color.White;
this.lblRefreshRate.Location = new System.Drawing.Point(24, 280);
this.lblRefreshRate.Name = "lblRefreshRate";
this.lblRefreshRate.Size = new System.Drawing.Size(72, 15);
this.lblRefreshRate.TabIndex = 11;
this.lblRefreshRate.Text = "Refresh Rate";
//
// RefreshRateComboBox
//
this.RefreshRateComboBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.RefreshRateComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.RefreshRateComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.RefreshRateComboBox.Font = new System.Drawing.Font("Segoe UI", 9F);
this.RefreshRateComboBox.ForeColor = System.Drawing.Color.White;
this.RefreshRateComboBox.FormattingEnabled = true;
this.RefreshRateComboBox.Items.AddRange(new object[] {
"72 Hz",
"90 Hz",
"120 Hz"});
this.RefreshRateComboBox.Location = new System.Drawing.Point(24, 298);
this.RefreshRateComboBox.Name = "RefreshRateComboBox";
this.RefreshRateComboBox.Size = new System.Drawing.Size(130, 23);
this.RefreshRateComboBox.TabIndex = 12;
//
// lblGpuLevel
//
this.lblGpuLevel.AutoSize = true;
this.lblGpuLevel.Font = new System.Drawing.Font("Segoe UI", 9F);
this.lblGpuLevel.ForeColor = System.Drawing.Color.White;
this.lblGpuLevel.Location = new System.Drawing.Point(170, 280);
this.lblGpuLevel.Name = "lblGpuLevel";
this.lblGpuLevel.Size = new System.Drawing.Size(60, 15);
this.lblGpuLevel.TabIndex = 13;
this.lblGpuLevel.Text = "GPU Level";
//
// GPUComboBox
//
this.GPUComboBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.GPUComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.GPUComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.GPUComboBox.Font = new System.Drawing.Font("Segoe UI", 9F);
this.GPUComboBox.ForeColor = System.Drawing.Color.White;
this.GPUComboBox.FormattingEnabled = true;
this.GPUComboBox.Items.AddRange(new object[] {
"0 (Default)",
"1",
"2",
"3",
"4"});
this.GPUComboBox.Location = new System.Drawing.Point(170, 298);
this.GPUComboBox.Name = "GPUComboBox";
this.GPUComboBox.Size = new System.Drawing.Size(130, 23);
this.GPUComboBox.TabIndex = 14;
//
// lblCpuLevel
//
this.lblCpuLevel.AutoSize = true;
this.lblCpuLevel.Font = new System.Drawing.Font("Segoe UI", 9F);
this.lblCpuLevel.ForeColor = System.Drawing.Color.White;
this.lblCpuLevel.Location = new System.Drawing.Point(24, 330);
this.lblCpuLevel.Name = "lblCpuLevel";
this.lblCpuLevel.Size = new System.Drawing.Size(60, 15);
this.lblCpuLevel.TabIndex = 15;
this.lblCpuLevel.Text = "CPU Level";
//
// CPUComboBox
//
this.CPUComboBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.CPUComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.CPUComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.CPUComboBox.Font = new System.Drawing.Font("Segoe UI", 9F);
this.CPUComboBox.ForeColor = System.Drawing.Color.White;
this.CPUComboBox.FormattingEnabled = true;
this.CPUComboBox.Items.AddRange(new object[] {
"0 (Default)",
"1",
"2",
"3",
"4"});
this.CPUComboBox.Location = new System.Drawing.Point(24, 348);
this.CPUComboBox.Name = "CPUComboBox";
this.CPUComboBox.Size = new System.Drawing.Size(130, 23);
this.CPUComboBox.TabIndex = 16;
//
// lblResolution
//
this.lblResolution.AutoSize = true;
this.lblResolution.Font = new System.Drawing.Font("Segoe UI", 9F);
this.lblResolution.ForeColor = System.Drawing.Color.White;
this.lblResolution.Location = new System.Drawing.Point(170, 330);
this.lblResolution.Name = "lblResolution";
this.lblResolution.Size = new System.Drawing.Size(63, 15);
this.lblResolution.TabIndex = 17;
this.lblResolution.Text = "Resolution";
//
// TextureResTextBox
//
this.TextureResTextBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(44)))), ((int)(((byte)(52)))));
this.TextureResTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.TextureResTextBox.Font = new System.Drawing.Font("Segoe UI", 9F);
this.TextureResTextBox.ForeColor = System.Drawing.Color.White;
this.TextureResTextBox.Location = new System.Drawing.Point(170, 348);
this.TextureResTextBox.Name = "TextureResTextBox";
this.TextureResTextBox.Size = new System.Drawing.Size(130, 23);
this.TextureResTextBox.TabIndex = 18;
this.TextureResTextBox.Text = "0";
//
// btnApplyTempSettings
//
this.btnApplyTempSettings.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(113)))), ((int)(((byte)(223)))), ((int)(((byte)(193)))));
this.btnApplyTempSettings.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(113)))), ((int)(((byte)(223)))), ((int)(((byte)(193)))));
this.btnApplyTempSettings.BackColor = System.Drawing.Color.Transparent;
this.btnApplyTempSettings.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnApplyTempSettings.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnApplyTempSettings.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.btnApplyTempSettings.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.btnApplyTempSettings.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.btnApplyTempSettings.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.btnApplyTempSettings.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.btnApplyTempSettings.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.btnApplyTempSettings.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.btnApplyTempSettings.Location = new System.Drawing.Point(24, 385);
this.btnApplyTempSettings.Name = "btnApplyTempSettings";
this.btnApplyTempSettings.Radius = 5;
this.btnApplyTempSettings.Size = new System.Drawing.Size(130, 30);
this.btnApplyTempSettings.Stroke = false;
this.btnApplyTempSettings.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.btnApplyTempSettings.TabIndex = 10;
this.btnApplyTempSettings.Text = "APPLY SETTINGS";
this.btnApplyTempSettings.Transparency = false;
this.btnApplyTempSettings.Click += new System.EventHandler(this.btnApplyTempSettings_Click);
//
// separator1
//
this.separator1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.separator1.Location = new System.Drawing.Point(20, 85);
this.separator1.Name = "separator1";
this.separator1.Size = new System.Drawing.Size(295, 1);
this.separator1.TabIndex = 2;
//
// separator2
//
this.separator2.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.separator2.Location = new System.Drawing.Point(20, 220);
this.separator2.Name = "separator2";
this.separator2.Size = new System.Drawing.Size(295, 1);
this.separator2.TabIndex = 8;
//
// btnClose
//
this.btnClose.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(65)))), ((int)(((byte)(75)))));
this.btnClose.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(60)))), ((int)(((byte)(65)))), ((int)(((byte)(75)))));
this.btnClose.BackColor = System.Drawing.Color.Transparent;
this.btnClose.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnClose.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btnClose.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.btnClose.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.btnClose.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.btnClose.Font = new System.Drawing.Font("Segoe UI", 9F);
this.btnClose.ForeColor = System.Drawing.Color.White;
this.btnClose.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.btnClose.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.btnClose.Location = new System.Drawing.Point(170, 385);
this.btnClose.Name = "btnClose";
this.btnClose.Radius = 5;
this.btnClose.Size = new System.Drawing.Size(130, 30);
this.btnClose.Stroke = true;
this.btnClose.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
this.btnClose.TabIndex = 11;
this.btnClose.Text = "Close";
this.btnClose.Transparency = false;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// QuestForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.CancelButton = this.btnClose;
this.ClientSize = new System.Drawing.Size(340, 435);
this.Controls.Add(this.lblUsernameSection);
this.Controls.Add(this.GlobalUsername);
this.Controls.Add(this.btnApplyUsername);
this.Controls.Add(this.separator1);
this.Controls.Add(this.lblMediaSection);
this.Controls.Add(this.questPics);
this.Controls.Add(this.questVids);
this.Controls.Add(this.lblScreenshotsPath);
this.Controls.Add(this.lblRecordingsPath);
this.Controls.Add(this.toggleDeleteAfterTransfer);
this.Controls.Add(this.lblDeleteAfterTransfer);
this.Controls.Add(this.separator2);
this.Controls.Add(this.lblPerformanceSection);
this.Controls.Add(this.lblPerformanceNote);
this.Controls.Add(this.lblRefreshRate);
this.Controls.Add(this.RefreshRateComboBox);
this.Controls.Add(this.lblGpuLevel);
this.Controls.Add(this.GPUComboBox);
this.Controls.Add(this.lblCpuLevel);
this.Controls.Add(this.CPUComboBox);
this.Controls.Add(this.lblResolution);
this.Controls.Add(this.TextureResTextBox);
this.Controls.Add(this.btnApplyTempSettings);
this.Controls.Add(this.btnClose);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "QuestForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Quest Settings";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.QuestForm_FormClosed);
this.Load += new System.EventHandler(this.QuestForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
// Section Labels
private System.Windows.Forms.Label lblUsernameSection;
private System.Windows.Forms.Label lblMediaSection;
private System.Windows.Forms.Label lblPerformanceSection;
// Username controls
private System.Windows.Forms.TextBox GlobalUsername;
private RoundButton btnApplyUsername;
// Media controls
private RoundButton questPics;
private RoundButton questVids;
private System.Windows.Forms.Label lblScreenshotsPath;
private System.Windows.Forms.Label lblRecordingsPath;
private ToggleSwitch toggleDeleteAfterTransfer;
private System.Windows.Forms.Label lblDeleteAfterTransfer;
// Performance controls
private System.Windows.Forms.Label lblPerformanceNote;
private System.Windows.Forms.Label lblRefreshRate;
private System.Windows.Forms.ComboBox RefreshRateComboBox;
private System.Windows.Forms.Label lblGpuLevel;
private System.Windows.Forms.ComboBox GPUComboBox;
private System.Windows.Forms.Label lblCpuLevel;
private System.Windows.Forms.ComboBox CPUComboBox;
private System.Windows.Forms.Label lblResolution;
private System.Windows.Forms.TextBox TextureResTextBox;
private RoundButton btnApplyTempSettings;
// Separators
private System.Windows.Forms.Panel separator1;
private System.Windows.Forms.Panel separator2;
// Close button
private RoundButton btnClose;
}
namespace AndroidSideloader
{
partial class QuestForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.RefreshRateComboBox = new System.Windows.Forms.ComboBox();
this.button1 = new System.Windows.Forms.Button();
this.TextureResTextBox = new System.Windows.Forms.TextBox();
this.ResolutionLabel = new System.Windows.Forms.Label();
this.GPUComboBox = new System.Windows.Forms.ComboBox();
this.CPUComboBox = new System.Windows.Forms.ComboBox();
this.SuspendLayout();
//
// RefreshRateComboBox
//
this.RefreshRateComboBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.ComboBoxColor;
this.RefreshRateComboBox.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.RefreshRateComboBox.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.RefreshRateComboBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "ComboBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.RefreshRateComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.RefreshRateComboBox.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.RefreshRateComboBox.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.RefreshRateComboBox.FormattingEnabled = true;
this.RefreshRateComboBox.Items.AddRange(new object[] {
"72",
"90"});
this.RefreshRateComboBox.Location = new System.Drawing.Point(12, 12);
this.RefreshRateComboBox.Name = "RefreshRateComboBox";
this.RefreshRateComboBox.Size = new System.Drawing.Size(345, 26);
this.RefreshRateComboBox.TabIndex = 0;
this.RefreshRateComboBox.Text = "Select refresh rate";
//
// button1
//
this.button1.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
this.button1.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.button1.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.button1.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button1.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.button1.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.button1.Location = new System.Drawing.Point(12, 138);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(87, 34);
this.button1.TabIndex = 1;
this.button1.Text = "Apply";
this.button1.UseVisualStyleBackColor = false;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// TextureResTextBox
//
this.TextureResTextBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
this.TextureResTextBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "TextBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.TextureResTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.TextureResTextBox.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.TextureResTextBox.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.TextureResTextBox.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.TextureResTextBox.Location = new System.Drawing.Point(12, 108);
this.TextureResTextBox.Name = "TextureResTextBox";
this.TextureResTextBox.Size = new System.Drawing.Size(120, 24);
this.TextureResTextBox.TabIndex = 2;
this.TextureResTextBox.Text = "0";
//
// ResolutionLabel
//
this.ResolutionLabel.AutoSize = true;
this.ResolutionLabel.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.ResolutionLabel.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.ResolutionLabel.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.ResolutionLabel.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.ResolutionLabel.Location = new System.Drawing.Point(135, 114);
this.ResolutionLabel.Name = "ResolutionLabel";
this.ResolutionLabel.Size = new System.Drawing.Size(222, 18);
this.ResolutionLabel.TabIndex = 3;
this.ResolutionLabel.Text = "Resolution per eye (0 for default)";
//
// GPUComboBox
//
this.GPUComboBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.ComboBoxColor;
this.GPUComboBox.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.GPUComboBox.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.GPUComboBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "ComboBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.GPUComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.GPUComboBox.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.GPUComboBox.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.GPUComboBox.FormattingEnabled = true;
this.GPUComboBox.Items.AddRange(new object[] {
"0",
"1",
"2",
"3",
"4"});
this.GPUComboBox.Location = new System.Drawing.Point(12, 44);
this.GPUComboBox.Name = "GPUComboBox";
this.GPUComboBox.Size = new System.Drawing.Size(345, 26);
this.GPUComboBox.TabIndex = 4;
this.GPUComboBox.Text = "Select GPU level (0 for default)";
//
// CPUComboBox
//
this.CPUComboBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.ComboBoxColor;
this.CPUComboBox.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.CPUComboBox.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.CPUComboBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "ComboBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.CPUComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.CPUComboBox.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.CPUComboBox.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.CPUComboBox.FormattingEnabled = true;
this.CPUComboBox.Items.AddRange(new object[] {
"0",
"1",
"2",
"3",
"4"});
this.CPUComboBox.Location = new System.Drawing.Point(12, 76);
this.CPUComboBox.Name = "CPUComboBox";
this.CPUComboBox.Size = new System.Drawing.Size(345, 26);
this.CPUComboBox.TabIndex = 5;
this.CPUComboBox.Text = "Select CPU level (0 for default)";
//
// QuestForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
this.ClientSize = new System.Drawing.Size(371, 185);
this.Controls.Add(this.CPUComboBox);
this.Controls.Add(this.GPUComboBox);
this.Controls.Add(this.ResolutionLabel);
this.Controls.Add(this.TextureResTextBox);
this.Controls.Add(this.button1);
this.Controls.Add(this.RefreshRateComboBox);
this.MaximumSize = new System.Drawing.Size(387, 224);
this.MinimumSize = new System.Drawing.Size(387, 224);
this.Name = "QuestForm";
this.ShowIcon = false;
this.Text = "QuestForm";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox RefreshRateComboBox;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox TextureResTextBox;
private System.Windows.Forms.Label ResolutionLabel;
private System.Windows.Forms.ComboBox GPUComboBox;
private System.Windows.Forms.ComboBox CPUComboBox;
}
}

View File

@@ -1,199 +1,51 @@
using AndroidSideloader.Utilities;
using System;
using System.IO;
using System;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class QuestForm : Form
{
private static readonly SettingsManager settings = SettingsManager.Instance;
public static int length = 0;
public static string[] result;
public bool settingsexist = false;
private bool delsh = false;
public QuestForm()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
}
private void btnApplyTempSettings_Click(object sender, EventArgs e)
private void button1_Click(object sender, EventArgs e)
{
bool ChangesMade = false;
if (RefreshRateComboBox.SelectedIndex != -1)
{
string refreshRate = RefreshRateComboBox.SelectedItem.ToString().Replace(" Hz", "");
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.refreshRate {refreshRate}");
_ = ADB.RunAdbCommandToString($"shell settings put global 90hz_global {RefreshRateComboBox.SelectedIndex}");
_ = ADB.RunAdbCommandToString($"shell settings put global 90hzglobal {RefreshRateComboBox.SelectedIndex}");
ADB.RunAdbCommandToString($"shell setprop debug.oculus.refreshRate {RefreshRateComboBox.SelectedItem.ToString()}");
ADB.RunAdbCommandToString($"shell settings put global 90hz_global {RefreshRateComboBox.SelectedIndex}");
ADB.RunAdbCommandToString($"shell settings put global 90hzglobal {RefreshRateComboBox.SelectedIndex}");
ChangesMade = true;
}
if (TextureResTextBox.Text.Length > 0 && TextureResTextBox.Text != "0")
if (TextureResTextBox.Text.Length>0)
{
if (int.TryParse(TextureResTextBox.Text, out _))
{
_ = ADB.RunAdbCommandToString($"shell settings put global texture_size_Global {TextureResTextBox.Text}");
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureWidth {TextureResTextBox.Text}");
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureHeight {TextureResTextBox.Text}");
ChangesMade = true;
}
Int32.TryParse(TextureResTextBox.Text, out int result);
ADB.RunAdbCommandToString($"shell settings put global texture_size_Global {TextureResTextBox.Text}");
ADB.RunAdbCommandToString($"shell settings put global texture_size_Global {TextureResTextBox.Text}");
ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureWidth {TextureResTextBox.Text}");
ADB.RunAdbCommandToString($"shell setprop debug.oculus.textureHeight {TextureResTextBox.Text}");
ChangesMade = true;
}
if (CPUComboBox.SelectedIndex != -1)
{
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.cpuLevel {CPUComboBox.SelectedIndex}");
ADB.RunAdbCommandToString($"shell setprop debug.oculus.cpuLevel {CPUComboBox.SelectedItem.ToString()}");
ChangesMade = true;
}
if (GPUComboBox.SelectedIndex != -1)
{
_ = ADB.RunAdbCommandToString($"shell setprop debug.oculus.gpuLevel {GPUComboBox.SelectedIndex}");
ADB.RunAdbCommandToString($"shell setprop debug.oculus.gpuLevel {GPUComboBox.SelectedItem.ToString()}");
ChangesMade = true;
}
if (ChangesMade)
{
_ = MessageBox.Show("Settings applied!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
public static void setLength(int value)
{
result = new string[value];
}
private void toggleDeleteAfterTransfer_CheckedChanged(object sender, EventArgs e)
{
delsh = toggleDeleteAfterTransfer.Checked;
}
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static int RandomNumber(int min, int max)
{
lock (syncLock)
{
return random.Next(min, max);
}
}
private void QuestForm_FormClosed(object sender, FormClosedEventArgs e)
{
settings.Delsh = toggleDeleteAfterTransfer.Checked;
settings.Save();
}
private void QuestForm_Load(object sender, EventArgs e)
{
CenterToParent();
toggleDeleteAfterTransfer.SetCheckedSilent(settings.Delsh);
delsh = settings.Delsh;
GlobalUsername.Text = settings.GlobalUsername;
}
private void questPics_Click(object sender, EventArgs e)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (!Directory.Exists($"{path}\\Quest Screenshots"))
{
_ = Directory.CreateDirectory($"{path}\\Quest Screenshots");
}
_ = MessageBox.Show("Please wait until you get the message that the transfer has finished.",
"Transfer Starting", MessageBoxButtons.OK, MessageBoxIcon.Information);
Program.form.changeTitle("Pulling files...");
_ = ADB.RunAdbCommandToString($"pull \"/sdcard/Oculus/Screenshots\" \"{path}\\Quest Screenshots\"");
if (delsh)
{
DialogResult dialogResult = MessageBox.Show(
"You have chosen to delete files from headset after transferring.\n\nMake sure to move them from your desktop to somewhere safe!",
"Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
if (dialogResult == DialogResult.OK)
{
_ = ADB.RunAdbCommandToString("shell rm -r /sdcard/Oculus/Screenshots");
_ = ADB.RunAdbCommandToString("shell mkdir /sdcard/Oculus/Screenshots");
}
}
_ = MessageBox.Show("Transfer finished!\n\nScreenshots can be found in:\nDesktop\\Quest Screenshots",
"Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
Program.form.changeTitle("Done!");
}
private void questVids_Click(object sender, EventArgs e)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
if (!Directory.Exists($"{path}\\Quest Recordings"))
{
_ = Directory.CreateDirectory($"{path}\\Quest Recordings");
}
_ = MessageBox.Show("Please wait until you get the message that the transfer has finished.",
"Transfer Starting", MessageBoxButtons.OK, MessageBoxIcon.Information);
Program.form.changeTitle("Pulling files...");
_ = ADB.RunAdbCommandToString($"pull \"/sdcard/Oculus/Videoshots\" \"{path}\\Quest Recordings\"");
if (delsh)
{
DialogResult dialogResult = MessageBox.Show(
"You have chosen to delete files from headset after transferring.\n\nMake sure to move them from your desktop to somewhere safe!",
"Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
if (dialogResult == DialogResult.OK)
{
_ = ADB.RunAdbCommandToString("shell rm -r /sdcard/Oculus/Videoshots");
_ = ADB.RunAdbCommandToString("shell mkdir /sdcard/Oculus/Videoshots");
}
}
_ = MessageBox.Show("Transfer finished!\n\nRecordings can be found in:\nDesktop\\Quest Recordings",
"Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
Program.form.changeTitle("Done!");
}
private void btnApplyUsername_Click(object sender, EventArgs e)
{
_ = ADB.RunAdbCommandToString($"shell settings put global username {GlobalUsername.Text}");
_ = MessageBox.Show($"Username set to: {GlobalUsername.Text}", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}
protected override bool ProcessDialogKey(Keys keyData)
{
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
{
Close();
return true;
}
return base.ProcessDialogKey(keyData);
}
private void GlobalUsername_TextChanged(object sender, EventArgs e)
{
btnApplyUsername.Enabled = GlobalUsername.TextLength > 0;
btnApplyUsername.ForeColor = System.Drawing.Color.FromArgb(
((int)(((byte)(btnApplyUsername.Enabled ? 30 : 80)))),
((int)(((byte)(btnApplyUsername.Enabled ? 24 : 80)))),
((int)(((byte)(btnApplyUsername.Enabled ? 29 : 80)))));
settings.GlobalUsername = GlobalUsername.Text;
MessageBox.Show("Settings applied!");
}
}
}
}

353
RCLONE.cs
View File

@@ -1,46 +1,18 @@
using AndroidSideloader.Utilities;
using JR.Utils.GUI.Forms;
using System;
using System;
using System.Diagnostics;
using System.IO;
using System.Management;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace AndroidSideloader
{
internal class RCLONE
class RCLONE
{
private static readonly SettingsManager settings = SettingsManager.Instance;
// Kill RCLONE Processes that were started from Rookie by looking for child processes.
public static void killRclone()
{
var parentProcessId = Process.GetCurrentProcess().Id;
var processes = Process.GetProcessesByName("rclone");
foreach (var process in processes)
{
try
{
using (ManagementObject obj = new ManagementObject($"win32_process.handle='{process.Id}'"))
{
obj.Get();
var ppid = Convert.ToInt32(obj["ParentProcessId"]);
if (ppid == parentProcessId)
{
process.Kill();
}
}
}
catch (Exception ex)
{
_ = Logger.Log($"Exception occured while attempting to shut down RCLONE with exception message: {ex.Message}", LogLevel.ERROR);
}
}
foreach (var process in Process.GetProcessesByName("rclone"))
process.Kill();
}
// For custom configs that use a password
public static void Init()
{
string PwTxtPath = Path.Combine(Environment.CurrentDirectory, "rclone\\pw.txt");
@@ -50,342 +22,73 @@ namespace AndroidSideloader
}
}
// Change if you want to use a config
public static string downloadConfigPath = "vrp.download.config";
public static string uploadConfigPath = "vrp.upload.config";
public static string configPath = ""; // ".\\a"
public static string rclonepw = "";
private static readonly Process rclone = new Process();
private static Process rclone = new Process();
// Run an RCLONE Command that accesses the Download Config.
public static ProcessOutput runRcloneCommand_DownloadConfig(string command)
public static ProcessOutput runRcloneCommand(string command, string bandwithLimit = "")
{
if (MainForm.isOffline)
{
return new ProcessOutput("", "No internet");
}
ProcessOutput prcoutput = new ProcessOutput();
// Rclone output is unicode, else it will show garbage instead of unicode characters
Environment.SetEnvironmentVariable("RCLONE_CRYPT_REMOTE", rclonepw);
Environment.SetEnvironmentVariable("RCLONE_CONFIG_PASS", rclonepw);
ProcessOutput prcoutput = new ProcessOutput("","");
rclone.StartInfo.StandardOutputEncoding = Encoding.UTF8;
string originalCommand = command;
// set configpath if there is any
if (downloadConfigPath.Length > 0)
if (bandwithLimit.Length > 0)
{
command += $" --config {downloadConfigPath}";
command += $" --bwlimit={bandwithLimit}";
}
command += $" --inplace";
if (configPath.Length > 0)
{
command += $" --config {configPath}";
}
// set rclonepw
if (rclonepw.Length > 0)
{
command += " --ask-password=false";
}
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
if (logcmd.Contains($"\"{settings.CurrentLogPath}\""))
{
logcmd = logcmd.Replace($"\"{settings.CurrentLogPath}\"", $"\"{settings.CurrentLogName}\"");
}
Logger.Log($"Running Rclone command: {command}");
if (logcmd.Contains(Environment.CurrentDirectory))
{
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
}
_ = Logger.Log($"Running Rclone command: {logcmd}");
rclone.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "rclone", "rclone.exe");
rclone.StartInfo.FileName = Environment.CurrentDirectory + "\\rclone\\rclone.exe";
rclone.StartInfo.Arguments = command;
rclone.StartInfo.RedirectStandardInput = true;
rclone.StartInfo.RedirectStandardError = true;
rclone.StartInfo.RedirectStandardOutput = true;
rclone.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "rclone");
rclone.StartInfo.WorkingDirectory = Environment.CurrentDirectory + "\\rclone";
rclone.StartInfo.CreateNoWindow = true;
setRcloneProxy();
// Display RCLONE Window if the binary is being run in Debug Mode.
if (MainForm.debugMode)
{
if (MainForm.debugMode == true)
rclone.StartInfo.CreateNoWindow = false;
}
rclone.StartInfo.UseShellExecute = false;
_ = rclone.Start();
rclone.Start();
rclone.StandardInput.WriteLine(command);
rclone.StandardInput.Flush();
rclone.StandardInput.Close();
string output = rclone.StandardOutput.ReadToEnd();
string error = rclone.StandardError.ReadToEnd();
rclone.WaitForExit();
if (error.Contains("There is not enough space"))
{
Program.form.Invoke(() =>
{
_ = FlexibleMessageBox.Show(Program.form, $"There isn't enough disk space to download this game.\r\nPlease ensure you have at least 200MB more the game size available in {settings.DownloadDir} and try again.",
"NOT ENOUGH SPACE",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
});
return new ProcessOutput("Download failed.", "");
}
// Switch mirror upon matching error output.
if (error.Contains("400 Bad Request") || error.Contains("cannot fetch token") || error.Contains("authError") || error.Contains("quota") || error.Contains("exceeded") || error.Contains("directory not found") || error.Contains("Failed to"))
if (error.Contains("cannot fetch token") || error.Contains("authError") || (error.Contains("quota") && error.Contains("exceeded")))
{
string oldRemote = MainForm.currentRemote;
bool retSM = false;
try
{
retSM = Program.form.SwitchMirrors();
Program.form.SwitchMirrors();
}
catch
{
return new ProcessOutput("All mirrors are on quota or down...", "All mirrors are on quota or down...");
}
if (retSM)
{
prcoutput = runRcloneCommand_DownloadConfig(originalCommand.Replace(oldRemote, MainForm.currentRemote));
}
prcoutput = runRcloneCommand(originalCommand.Replace(oldRemote, MainForm.currentRemote), bandwithLimit);
}
else
{
prcoutput.Output = output;
prcoutput.Error = error;
}
if (!output.Contains("Game Name;Release Name;") && !output.Contains("package:") && !output.Contains(".meta"))
{
if (!string.IsNullOrWhiteSpace(error))
{
_ = Logger.Log($"Rclone error: {error}\n", LogLevel.ERROR);
}
if (!string.IsNullOrWhiteSpace(output))
{
_ = Logger.Log($"Rclone Output: {output}");
}
}
Logger.Log($"Rclone error: {error}\nRclone Output: {output}");
return prcoutput;
}
public static ProcessOutput runRcloneCommand_UploadConfig(string command)
{
ProcessOutput prcoutput = new ProcessOutput();
// Rclone output is unicode, else it will show garbage instead of unicode characters
rclone.StartInfo.StandardOutputEncoding = Encoding.UTF8;
// set configpath if there is any
if (uploadConfigPath.Length > 0)
{
command += $" --config {uploadConfigPath}";
}
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
if (logcmd.Contains($"\"{settings.CurrentLogPath}\""))
{
logcmd = logcmd.Replace($"\"{settings.CurrentLogPath}\"", $"\"{settings.CurrentLogName}\"");
}
if (logcmd.Contains(Environment.CurrentDirectory))
{
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
}
_ = Logger.Log($"Running Rclone command: {logcmd}");
command += " --checkers 1 --retries 2 --inplace";
rclone.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "rclone", "rclone.exe");
rclone.StartInfo.Arguments = command;
rclone.StartInfo.RedirectStandardInput = true;
rclone.StartInfo.RedirectStandardError = true;
rclone.StartInfo.RedirectStandardOutput = true;
rclone.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "rclone");
rclone.StartInfo.CreateNoWindow = true;
setRcloneProxy();
// Display RCLONE Window if the binary is being run in Debug Mode.
if (MainForm.debugMode)
{
rclone.StartInfo.CreateNoWindow = false;
}
rclone.StartInfo.UseShellExecute = false;
_ = rclone.Start();
rclone.StandardInput.WriteLine(command);
rclone.StandardInput.Flush();
rclone.StandardInput.Close();
string output = rclone.StandardOutput.ReadToEnd();
string error = rclone.StandardError.ReadToEnd();
rclone.WaitForExit();
// if there is one of these errors, we switch the mirrors
if (error.Contains("400 Bad Request") || error.Contains("cannot fetch token") || error.Contains("authError") || error.Contains("quota") || error.Contains("exceeded") || error.Contains("directory not found") || error.Contains("Failed to"))
{
_ = Logger.Log(error, LogLevel.ERROR);
return new ProcessOutput("Upload Failed.", "Upload failed.");
}
else
{
prcoutput.Output = output;
prcoutput.Error = error;
}
if (!output.Contains("Game Name;Release Name;") && !output.Contains("package:") && !output.Contains(".meta"))
{
if (!string.IsNullOrWhiteSpace(error))
{
_ = Logger.Log($"Rclone error: {error}\n", LogLevel.ERROR);
}
if (!string.IsNullOrWhiteSpace(output))
{
_ = Logger.Log($"Rclone Output: {output}");
}
}
return prcoutput;
}
public static ProcessOutput runRcloneCommand_PublicConfig(string command)
{
if (MainForm.isOffline)
{
return new ProcessOutput("", "No internet");
}
ProcessOutput prcoutput = new ProcessOutput();
// Rclone output is unicode, else it will show garbage instead of unicode characters
rclone.StartInfo.StandardOutputEncoding = Encoding.UTF8;
string logcmd = Utilities.StringUtilities.RemoveEverythingBeforeFirst(command, "rclone.exe");
if (logcmd.Contains($"\"{settings.CurrentLogPath}\""))
{
logcmd = logcmd.Replace($"\"{settings.CurrentLogPath}\"", $"\"{settings.CurrentLogName}\"");
}
if (logcmd.Contains(Environment.CurrentDirectory))
{
logcmd = logcmd.Replace($"{Environment.CurrentDirectory}", $"CurrentDirectory");
}
command += $" --inplace";
_ = Logger.Log($"Running Rclone command: {logcmd}");
//set http source & args
command += $" --http-url {MainForm.PublicConfigFile.BaseUri} {MainForm.PublicMirrorExtraArgs}";
rclone.StartInfo.FileName = Path.Combine(Environment.CurrentDirectory, "rclone", "rclone.exe");
rclone.StartInfo.Arguments = command;
rclone.StartInfo.RedirectStandardInput = true;
rclone.StartInfo.RedirectStandardError = true;
rclone.StartInfo.RedirectStandardOutput = true;
rclone.StartInfo.WorkingDirectory = Path.Combine(Environment.CurrentDirectory, "rclone");
rclone.StartInfo.CreateNoWindow = true;
setRcloneProxy();
// Display RCLONE Window if the binary is being run in Debug Mode.
if (MainForm.debugMode)
{
rclone.StartInfo.CreateNoWindow = false;
}
rclone.StartInfo.UseShellExecute = false;
_ = rclone.Start();
rclone.StandardInput.WriteLine(command);
rclone.StandardInput.Flush();
rclone.StandardInput.Close();
string output = rclone.StandardOutput.ReadToEnd();
string error = rclone.StandardError.ReadToEnd();
rclone.WaitForExit();
if (error.Contains("There is not enough space"))
{
Program.form.Invoke(() =>
{
_ = FlexibleMessageBox.Show(Program.form, $"There isn't enough disk space to download this game.\r\nPlease ensure you have at least 2x the game size available in {settings.DownloadDir} and try again.",
"NOT ENOUGH SPACE",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
});
return new ProcessOutput("Download failed.", string.Empty);
}
if (error.Contains("Only one usage of each socket address (protocol/network address/port) is normally permitted"))
{
_ = Logger.Log(error, LogLevel.ERROR);
return new ProcessOutput("Failed to fetch from public mirror.", "Failed to fetch from public mirror.\nYou may have a running RCLONE Task!\nCheck your Task Manager, Sort by Network Usage, and kill the process Rsync for Cloud Storage/Rclone");
}
else if (error.Contains("400 Bad Request")
|| error.Contains("cannot fetch token")
|| error.Contains("authError")
|| error.Contains("quota")
|| error.Contains("exceeded")
|| error.Contains("directory not found")
|| error.Contains("Failed to"))
{
_ = Logger.Log(error, LogLevel.ERROR);
return new ProcessOutput("Failed to fetch from public mirror.", "Failed to fetch from public mirror.");
}
else
{
prcoutput.Output = output;
prcoutput.Error = error;
}
if (!output.Contains("Game Name;Release Name;") && !output.Contains("package:") && !output.Contains(".meta"))
{
if (!string.IsNullOrWhiteSpace(error))
{
_ = Logger.Log($"Rclone error: {error}\n", LogLevel.ERROR);
}
if (!string.IsNullOrWhiteSpace(output))
{
_ = Logger.Log($"Rclone Output: {output}");
}
}
return prcoutput;
}
private static void setRcloneProxy()
{
// Use the user's proxy settings if set, otherwise fallback to DNS fallback proxy if active
string proxyUrl = DnsHelper.ProxyUrl;
if (settings.useProxy)
{
// Use user's configured proxy
var url = $"http://{settings.ProxyAddress}:{settings.ProxyPort}";
rclone.StartInfo.EnvironmentVariables["HTTP_PROXY"] = url;
rclone.StartInfo.EnvironmentVariables["HTTPS_PROXY"] = url;
rclone.StartInfo.EnvironmentVariables["http_proxy"] = url;
rclone.StartInfo.EnvironmentVariables["https_proxy"] = url;
}
else if (!string.IsNullOrEmpty(proxyUrl))
{
// Use our DNS-resolving proxy
rclone.StartInfo.EnvironmentVariables["HTTP_PROXY"] = proxyUrl;
rclone.StartInfo.EnvironmentVariables["HTTPS_PROXY"] = proxyUrl;
rclone.StartInfo.EnvironmentVariables["http_proxy"] = proxyUrl;
rclone.StartInfo.EnvironmentVariables["https_proxy"] = proxyUrl;
}
else
{
// No proxy
rclone.StartInfo.EnvironmentVariables.Remove("HTTP_PROXY");
rclone.StartInfo.EnvironmentVariables.Remove("HTTPS_PROXY");
rclone.StartInfo.EnvironmentVariables.Remove("http_proxy");
rclone.StartInfo.EnvironmentVariables.Remove("https_proxy");
}
}
}
}

View File

@@ -1,33 +0,0 @@
# AndroidSideloader
![GitHub last commit](https://img.shields.io/github/last-commit/VRPirates/rookie)
![GitHub release (latest by date)](https://img.shields.io/github/v/release/VRPirates/rookie)
[![Downloads](https://img.shields.io/github/downloads/VRPirates/rookie/total.svg)](https://github.com/VRPirates/rookie/releases)
![Issues](https://img.shields.io/github/issues/VRPirates/rookie)
## Disclaimer
This application might get flagged as malware by some antivirus software; however, both the Sideloader and the Sideloader Launcher are open source.
To run properly, Rookie must be extracted to a non-Protected folder on your drive. We recommend running Rookie from C:\RSL\Rookie
Do Not use folders such as- C:\Users; C:\Users\Desktop; C:\Program Files; OneDrive; Google Drive; etc...
Rookie will cleanup its own folder. We are not responsible if you run Rookie from a folder containing other files as Rookie may delete them.
## Support
For any assistance or questions, please utilize our support channels available at [Live Chats](https://vrpirates.wiki/en/general_information/live-chats).
## Build Instructions
This project is developed using C# with WinForms targeting the .NET Framework 4.5.2. To build the project successfully in Visual Studio 2022, follow these steps:
1. Clone this repository to your local machine.
2. Ensure you have the .NET Framework 4.5.2 installed on your machine.
3. Open the solution file (`*.sln`) in Visual Studio 2022.
4. Sometimes the building process can fail due to the packages.config, you should migrate it to PackageReference, do this by right clicking on References in the Solution Explorer, and pressing "Migrate packages.config to PackageReference"
5. Build the solution by selecting "Build" > "Build Solution" from the Visual Studio menu or pressing `Ctrl + Shift + B`. (or right click the solution in the solution explorer, then press Build)
6. Run the application.
## Contributing
We welcome contributions from the community. If you would like to contribute, please fork the repository, branch from the newest beta branch from this repository, make your changes, and submit a pull request.
## License
AndroidSideloader is distributed under the GPL license, meaning any forks of it must have their source code made public on the internet. See the [LICENSE](LICENSE) file for details.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

View File

@@ -1,10 +0,0 @@
@echo off
for /f "tokens=* usebackq" %%f in (`dir /b AndroidSideloader*.exe`) do (set "sideloader=%%f" & goto :next)
:next
echo %sideloader%
start "" "%sideloader%" "--offline"

View File

@@ -1,336 +0,0 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AndroidSideloader
{
[Description("Rounded Button")]
public class RoundButton : Control, IButtonControl
{
#region Variables
private int radius;
private MouseState state;
private RoundedRectangleF roundedRect;
private Color inactive1, inactive2, active1, active2;
private Color strokeColor;
private bool stroke;
public bool Stroke
{
get => stroke;
set
{
stroke = value;
Invalidate();
}
}
public Color StrokeColor
{
get => strokeColor;
set
{
strokeColor = value;
Invalidate();
}
}
private Color disabled1, disabled2;
private Color disabledStrokeColor;
public Color Disabled1
{
get => disabled1;
set
{
disabled1 = value;
Invalidate();
}
}
public Color Disabled2
{
get => disabled2;
set
{
disabled2 = value;
Invalidate();
}
}
public Color DisabledStrokeColor
{
get => disabledStrokeColor;
set
{
disabledStrokeColor = value;
Invalidate();
}
}
#endregion
#region RoundButton
public RoundButton()
{
Width = 65;
Height = 30;
stroke = false;
strokeColor = Color.Gray;
inactive1 = Color.FromArgb(44, 188, 210);
inactive2 = Color.FromArgb(33, 167, 188);
active1 = Color.FromArgb(64, 168, 183);
active2 = Color.FromArgb(36, 164, 183);
disabled1 = Color.FromArgb(32, 35, 45);
disabled2 = Color.FromArgb(25, 28, 35);
disabledStrokeColor = Color.FromArgb(50, 55, 65);
radius = 10;
roundedRect = new RoundedRectangleF(Width, Height, radius);
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor |
ControlStyles.UserPaint, true);
BackColor = Color.Transparent;
ForeColor = Color.Black;
Font = new System.Drawing.Font("Comic Sans MS", 10, FontStyle.Bold);
state = MouseState.Leave;
Transparency = false;
}
#endregion
#region Events
protected override void OnPaint(PaintEventArgs e)
{
#region Transparency
if (Transparency)
{
Transparenter.MakeTransparent(this, e.Graphics);
}
#endregion
#region Drawing
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
roundedRect = new RoundedRectangleF(Width, Height, radius);
e.Graphics.FillRectangle(Brushes.Transparent, ClientRectangle);
int R1 = (active1.R + inactive1.R) / 2;
int G1 = (active1.G + inactive1.G) / 2;
int B1 = (active1.B + inactive1.B) / 2;
int R2 = (active2.R + inactive2.R) / 2;
int G2 = (active2.G + inactive2.G) / 2;
int B2 = (active2.B + inactive2.B) / 2;
Rectangle rect = new Rectangle(0, 0, Width, Height);
if (Enabled)
{
if (state == MouseState.Leave)
{
using (LinearGradientBrush inactiveGB = new LinearGradientBrush(rect, inactive1, inactive2, 90f))
{
e.Graphics.FillPath(inactiveGB, roundedRect.Path);
}
}
else if (state == MouseState.Enter)
{
using (LinearGradientBrush activeGB = new LinearGradientBrush(rect, active1, active2, 90f))
{
e.Graphics.FillPath(activeGB, roundedRect.Path);
}
}
else if (state == MouseState.Down)
{
using (LinearGradientBrush downGB = new LinearGradientBrush(rect, Color.FromArgb(R1, G1, B1), Color.FromArgb(R2, G2, B2), 90f))
{
e.Graphics.FillPath(downGB, roundedRect.Path);
}
}
if (stroke)
{
using (Pen pen = new Pen(strokeColor, 1))
using (GraphicsPath path = new RoundedRectangleF(Width - (radius > 0 ? 0 : 1), Height - (radius > 0 ? 0 : 1), radius).Path)
{
e.Graphics.DrawPath(pen, path);
}
}
}
else
{
using (LinearGradientBrush disabledGB = new LinearGradientBrush(rect, disabled1, disabled2, 90f))
{
e.Graphics.FillPath(disabledGB, roundedRect.Path);
}
if (stroke)
{
using (Pen pen = new Pen(disabledStrokeColor, 1))
using (GraphicsPath path = new RoundedRectangleF(Width - (radius > 0 ? 0 : 1), Height - (radius > 0 ? 0 : 1), radius).Path)
{
e.Graphics.DrawPath(pen, path);
}
}
}
#endregion
#region Text Drawing
using (StringFormat sf = new StringFormat()
{
LineAlignment = StringAlignment.Center,
Alignment = StringAlignment.Center,
})
using (Brush brush = new SolidBrush(ForeColor))
{
e.Graphics.DrawString(Text, Font, brush, ClientRectangle, sf);
}
#endregion
base.OnPaint(e);
}
protected override void OnMouseDoubleClick(MouseEventArgs e)
{
base.OnMouseDoubleClick(e);
base.OnClick(e);
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
}
protected override void OnEnabledChanged(EventArgs e)
{
Invalidate();
base.OnEnabledChanged(e);
}
protected override void OnResize(EventArgs e)
{
Invalidate();
base.OnResize(e);
}
protected override void OnMouseEnter(EventArgs e)
{
state = MouseState.Enter;
base.OnMouseEnter(e);
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
state = MouseState.Leave;
base.OnMouseLeave(e);
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
Capture = false;
state = MouseState.Down;
base.OnMouseDown(e);
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (state != MouseState.Leave)
{
state = MouseState.Enter;
}
base.OnMouseUp(e);
Invalidate();
}
#endregion
#region Properties
public int Radius
{
get => radius;
set
{
radius = value;
Invalidate();
}
}
public Color Inactive1
{
get => inactive1;
set
{
inactive1 = value;
Invalidate();
}
}
public Color Inactive2
{
get => inactive2;
set
{
inactive2 = value;
Invalidate();
}
}
public Color Active1
{
get => active1;
set
{
active1 = value;
Invalidate();
}
}
public Color Active2
{
get => active2;
set
{
active2 = value;
Invalidate();
}
}
public bool Transparency { get; set; }
public override string Text
{
get => base.Text;
set
{
base.Text = value;
Invalidate();
}
}
public override Color ForeColor
{
get => base.ForeColor;
set
{
base.ForeColor = value;
Invalidate();
}
}
public DialogResult DialogResult
{
get => System.Windows.Forms.DialogResult.OK;
set
{
}
}
public void NotifyDefault(bool value)
{
}
public void PerformClick()
{
OnClick(EventArgs.Empty);
}
#endregion
}
public enum MouseState
{
Enter,
Leave,
Down,
Up,
}
}

View File

@@ -1,48 +0,0 @@
using System.Drawing;
using System.Drawing.Drawing2D;
namespace AndroidSideloader
{
public class RoundedRectangleF
{
private Point location;
private readonly float x, y;
private readonly float width, height;
public RoundedRectangleF(float width, float height, float radius, float x = 0, float y = 0)
{
location = new Point(0, 0);
Radius = radius;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
Path = new GraphicsPath();
if (radius <= 0)
{
Path.AddRectangle(new RectangleF(x, y, width, height));
return;
}
RectangleF upperLeftRect = new RectangleF(x, y, 2 * radius, 2 * radius);
RectangleF upperRightRect = new RectangleF(width - (2 * radius) - 1, x, 2 * radius, 2 * radius);
RectangleF lowerLeftRect = new RectangleF(x, height - (2 * radius) - 1, 2 * radius, 2 * radius);
RectangleF lowerRightRect = new RectangleF(width - (2 * radius) - 1, height - (2 * radius) - 1, 2 * radius, 2 * radius);
Path.AddArc(upperLeftRect, 180, 90);
Path.AddArc(upperRightRect, 270, 90);
Path.AddArc(lowerRightRect, 0, 90);
Path.AddArc(lowerLeftRect, 90, 90);
Path.CloseAllFigures();
}
public RoundedRectangleF()
{
}
public GraphicsPath Path { get; }
public RectangleF Rect => new RectangleF(x, y, width, height);
public float Radius { get; set; }
}
}

View File

@@ -8,24 +8,23 @@ namespace AndroidSideloader
/// <summary>
/// Present the Windows Vista-style open file dialog to select a folder. Fall back for older Windows Versions
/// </summary>
//Coded by Erike from stackoverflow (https://stackoverflow.com/users/57611/erike)
public class FolderSelectDialog
{
private string _initialDirectory;
private string _title;
private string _fileName = "";
public string InitialDirectory
{
get => string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory;
set => _initialDirectory = value;
get { return string.IsNullOrEmpty(_initialDirectory) ? Environment.CurrentDirectory : _initialDirectory; }
set { _initialDirectory = value; }
}
public string Title
{
get => _title ?? "Select a folder";
set => _title = value;
get { return _title ?? "Select a folder"; }
set { _title = value; }
}
public string FileName { get; private set; } = "";
public string FileName { get { return _fileName; } }
public bool Show() { return Show(IntPtr.Zero); }
@@ -33,10 +32,10 @@ namespace AndroidSideloader
/// <returns>true if the user clicks OK</returns>
public bool Show(IntPtr hWndOwner)
{
ShowDialogResult result = Environment.OSVersion.Version.Major >= 6
var result = Environment.OSVersion.Version.Major >= 6
? VistaDialog.Show(hWndOwner, InitialDirectory, Title)
: ShowXpDialog(hWndOwner, InitialDirectory, Title);
FileName = result.FileName;
_fileName = result.FileName;
return result.Result;
}
@@ -48,13 +47,13 @@ namespace AndroidSideloader
private static ShowDialogResult ShowXpDialog(IntPtr ownerHandle, string initialDirectory, string title)
{
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog
var folderBrowserDialog = new FolderBrowserDialog
{
Description = title,
SelectedPath = initialDirectory,
ShowNewFolderButton = false
};
ShowDialogResult dialogResult = new ShowDialogResult();
var dialogResult = new ShowDialogResult();
if (folderBrowserDialog.ShowDialog(new WindowWrapper(ownerHandle)) == DialogResult.OK)
{
dialogResult.Result = true;
@@ -68,26 +67,26 @@ namespace AndroidSideloader
private const string c_foldersFilter = "Folders|\n";
private const BindingFlags c_flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
private static readonly Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
private static readonly Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
private static readonly MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
private static readonly MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
private static readonly MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
private static readonly MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
private static readonly uint s_fosPickFoldersBitFlag = (uint)s_windowsFormsAssembly
private readonly static Assembly s_windowsFormsAssembly = typeof(FileDialog).Assembly;
private readonly static Type s_iFileDialogType = s_windowsFormsAssembly.GetType("System.Windows.Forms.FileDialogNative+IFileDialog");
private readonly static MethodInfo s_createVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("CreateVistaDialog", c_flags);
private readonly static MethodInfo s_onBeforeVistaDialogMethodInfo = typeof(OpenFileDialog).GetMethod("OnBeforeVistaDialog", c_flags);
private readonly static MethodInfo s_getOptionsMethodInfo = typeof(FileDialog).GetMethod("GetOptions", c_flags);
private readonly static MethodInfo s_setOptionsMethodInfo = s_iFileDialogType.GetMethod("SetOptions", c_flags);
private readonly static uint s_fosPickFoldersBitFlag = (uint)s_windowsFormsAssembly
.GetType("System.Windows.Forms.FileDialogNative+FOS")
.GetField("FOS_PICKFOLDERS")
.GetValue(null);
private static readonly ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
private readonly static ConstructorInfo s_vistaDialogEventsConstructorInfo = s_windowsFormsAssembly
.GetType("System.Windows.Forms.FileDialog+VistaDialogEvents")
.GetConstructor(c_flags, null, new[] { typeof(FileDialog) }, null);
private static readonly MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
private static readonly MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
private static readonly MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");
private readonly static MethodInfo s_adviseMethodInfo = s_iFileDialogType.GetMethod("Advise");
private readonly static MethodInfo s_unAdviseMethodInfo = s_iFileDialogType.GetMethod("Unadvise");
private readonly static MethodInfo s_showMethodInfo = s_iFileDialogType.GetMethod("Show");
public static ShowDialogResult Show(IntPtr ownerHandle, string initialDirectory, string title)
{
OpenFileDialog openFileDialog = new OpenFileDialog
var openFileDialog = new OpenFileDialog
{
AddExtension = false,
CheckFileExists = false,
@@ -98,11 +97,11 @@ namespace AndroidSideloader
Title = title
};
object iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
_ = s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
_ = s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint)s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
object[] adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
_ = s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);
var iFileDialog = s_createVistaDialogMethodInfo.Invoke(openFileDialog, new object[] { });
s_onBeforeVistaDialogMethodInfo.Invoke(openFileDialog, new[] { iFileDialog });
s_setOptionsMethodInfo.Invoke(iFileDialog, new object[] { (uint)s_getOptionsMethodInfo.Invoke(openFileDialog, new object[] { }) | s_fosPickFoldersBitFlag });
var adviseParametersWithOutputConnectionToken = new[] { s_vistaDialogEventsConstructorInfo.Invoke(new object[] { openFileDialog }), 0U };
s_adviseMethodInfo.Invoke(iFileDialog, adviseParametersWithOutputConnectionToken);
try
{
@@ -115,7 +114,7 @@ namespace AndroidSideloader
}
finally
{
_ = s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
s_unAdviseMethodInfo.Invoke(iFileDialog, new[] { adviseParametersWithOutputConnectionToken[1] });
}
}
}
@@ -123,8 +122,9 @@ namespace AndroidSideloader
// Wrap an IWin32Window around an IntPtr
private class WindowWrapper : IWin32Window
{
public WindowWrapper(IntPtr handle) { Handle = handle; }
public IntPtr Handle { get; }
private readonly IntPtr _handle;
public WindowWrapper(IntPtr handle) { _handle = handle; }
public IntPtr Handle { get { return _handle; } }
}
}

View File

@@ -1,28 +0,0 @@
namespace AndroidSideloader.Properties {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Settings {
public Settings() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}

1196
SettingsForm.Designer.cs generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,400 +1,114 @@
using AndroidSideloader.Properties;
using AndroidSideloader.Utilities;
using JR.Utils.GUI.Forms;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class SettingsForm : Form
{
private static readonly SettingsManager _settings = SettingsManager.Instance;
public SettingsForm()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
}
private void SettingsForm_Load(object sender, EventArgs e)
{
CenterToParent();
initSettings();
initToolTips();
}
private void initSettings()
{
// Use SetCheckedSilent to avoid triggering events during initialization
toggleCheckForUpdates.SetCheckedSilent(_settings.CheckForUpdates);
toggleMessageBoxes.SetCheckedSilent(_settings.EnableMessageBoxes);
toggleDeleteAfterInstall.SetCheckedSilent(_settings.DeleteAllAfterInstall);
toggleUpdateConfig.SetCheckedSilent(_settings.AutoUpdateConfig);
toggleUserJson.SetCheckedSilent(_settings.UserJsonOnGameInstall);
toggleNoDeviceMode.SetCheckedSilent(_settings.NodeviceMode);
toggleBMBF.SetCheckedSilent(_settings.BMBFChecked);
toggleAutoReinstall.SetCheckedSilent(_settings.AutoReinstall);
toggleSingleThread.SetCheckedSilent(_settings.SingleThreadMode);
toggleVirtualFilesystem.SetCheckedSilent(_settings.VirtualFilesystemCompatibility);
toggleUseDownloadedFiles.SetCheckedSilent(_settings.UseDownloadedFiles);
toggleTrailers.SetCheckedSilent(_settings.TrailersEnabled);
bandwidthLimitTextBox.Text = _settings.BandwidthLimit.ToString();
// Handle no device mode disabling delete after install
if (toggleNoDeviceMode.Checked)
{
toggleDeleteAfterInstall.SetCheckedSilent(false);
toggleDeleteAfterInstall.Enabled = false;
lblDeleteAfterInstall.ForeColor = System.Drawing.Color.FromArgb(100, 100, 100);
}
toggleProxy.Checked = _settings.useProxy;
proxyAddressTextBox.Text = _settings.ProxyAddress;
proxyPortTextBox.Text = _settings.ProxyPort;
}
private void initToolTips()
{
ToolTip toolTip = new ToolTip();
toolTip.SetToolTip(toggleCheckForUpdates, "Check for available application updates on startup");
toolTip.SetToolTip(lblCheckForUpdates, "Check for available application updates on startup");
toolTip.SetToolTip(toggleMessageBoxes, "Show message boxes after every completed task");
toolTip.SetToolTip(lblMessageBoxes, "Show message boxes after every completed task");
toolTip.SetToolTip(toggleDeleteAfterInstall, "Delete game files after downloading and installing");
toolTip.SetToolTip(lblDeleteAfterInstall, "Delete game files after downloading and installing");
toolTip.SetToolTip(toggleUseDownloadedFiles, "Always install downloaded files without prompting to re-download");
toolTip.SetToolTip(lblUseDownloadedFiles, "Always install downloaded files without prompting to re-download");
toolTip.SetToolTip(toggleTrailers, "Show game trailers when selecting a game");
toolTip.SetToolTip(lblTrailers, "Show game trailers when selecting a game");
}
private void SaveAllSettings()
{
string input = bandwidthLimitTextBox.Text;
Regex regex = new Regex(@"^\d+(\.\d+)?$");
if (regex.IsMatch(input) && float.TryParse(input, out float bandwidthLimit))
{
_settings.BandwidthLimit = bandwidthLimit;
}
_settings.CheckForUpdates = toggleCheckForUpdates.Checked;
_settings.EnableMessageBoxes = toggleMessageBoxes.Checked;
_settings.DeleteAllAfterInstall = toggleDeleteAfterInstall.Checked;
_settings.AutoUpdateConfig = toggleUpdateConfig.Checked;
_settings.UserJsonOnGameInstall = toggleUserJson.Checked;
_settings.NodeviceMode = toggleNoDeviceMode.Checked;
_settings.BMBFChecked = toggleBMBF.Checked;
_settings.AutoReinstall = toggleAutoReinstall.Checked;
_settings.SingleThreadMode = toggleSingleThread.Checked;
_settings.VirtualFilesystemCompatibility = toggleVirtualFilesystem.Checked;
_settings.UseDownloadedFiles = toggleUseDownloadedFiles.Checked;
_settings.TrailersEnabled = toggleTrailers.Checked;
_settings.useProxy = toggleProxy.Checked;
if (Program.form != null)
{
Program.form.SetTrailerVisibility(toggleTrailers.Checked);
Program.form.UpdateSideloadingUI();
}
if (_settings.AutoUpdateConfig)
{
_settings.CreatePubMirrorFile = true;
}
_settings.Save();
}
public void btnUploadDebug_click(object sender, EventArgs e)
{
if (File.Exists($"{_settings.CurrentLogPath}"))
{
string UUID = SideloaderUtilities.UUID();
string debugLogPath = $"{Environment.CurrentDirectory}\\{UUID}.log";
System.IO.File.Copy("debuglog.txt", debugLogPath);
Clipboard.SetText(UUID);
_ = RCLONE.runRcloneCommand_UploadConfig($"copy \"{debugLogPath}\" RSL-gameuploads:DebugLogs");
_ = MessageBox.Show($"Your debug log has been copied to the server. ID: {UUID}");
}
}
public void btnResetDebug_click(object sender, EventArgs e)
{
if (File.Exists($"{_settings.CurrentLogPath}"))
{
File.Delete($"{_settings.CurrentLogPath}");
}
if (File.Exists($"{Environment.CurrentDirectory}\\debuglog.txt"))
{
File.Delete($"{Environment.CurrentDirectory}\\debuglog.txt");
}
}
private void applyButton_Click(object sender, EventArgs e)
{
// Parse bandwidth value
var bandwidthInput = bandwidthLimitTextBox.Text;
Regex regex = new Regex(@"^\d+(\.\d+)?$");
if (regex.IsMatch(bandwidthInput) && float.TryParse(bandwidthInput, out float bandwidthLimit))
{
_settings.BandwidthLimit = bandwidthLimit;
}
else
{
MessageBox.Show("Please enter a valid number for the bandwidth limit.");
return;
}
// Parse proxy values if proxy is enabled
if (toggleProxy.Checked)
{
// Parse proxy address
var proxyAddressInput = proxyAddressTextBox.Text;
if (proxyAddressInput.StartsWith("http://"))
{
proxyAddressInput = proxyAddressInput.Substring("http://".Length);
}
else if (proxyAddressInput.StartsWith("https://"))
{
proxyAddressInput = proxyAddressInput.Substring("https://".Length);
}
if (proxyAddressInput.Equals("localhost", StringComparison.OrdinalIgnoreCase) ||
IPAddress.TryParse(proxyAddressInput, out _))
{
_settings.ProxyAddress = proxyAddressInput;
}
else
{
MessageBox.Show("Please enter a valid address for the proxy.");
}
// Parse proxy port
var proxyPortInput = proxyPortTextBox.Text;
if (ushort.TryParse(proxyPortInput, out _))
{
_settings.ProxyPort = proxyPortInput;
}
else
{
MessageBox.Show("Please enter a valid port for the proxy.");
}
}
SaveAllSettings();
this.Close();
}
private void toggleCheckForUpdates_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleUseDownloadedFiles_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleMessageBoxes_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleTrailers_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void resetSettingsButton_Click(object sender, EventArgs e)
{
this.Close();
}
private void toggleDeleteAfterInstall_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleUpdateConfig_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleUserJson_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void SettingsForm_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Escape)
{
Close();
}
}
private void SettingsForm_Leave(object sender, EventArgs e)
{
Close();
}
private void Form_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
Close();
}
}
protected override bool ProcessDialogKey(Keys keyData)
{
if (Form.ModifierKeys == Keys.None && keyData == Keys.Escape)
{
Close();
return true;
}
return base.ProcessDialogKey(keyData);
}
private void toggleNoDeviceMode_CheckedChanged(object sender, EventArgs e)
{
// Update UI state only - settings saved on form close
if (!toggleNoDeviceMode.Checked)
{
toggleDeleteAfterInstall.Checked = true;
toggleDeleteAfterInstall.Enabled = true;
lblDeleteAfterInstall.ForeColor = System.Drawing.Color.White;
}
else
{
toggleDeleteAfterInstall.SetCheckedSilent(false);
toggleDeleteAfterInstall.Enabled = false;
lblDeleteAfterInstall.ForeColor = System.Drawing.Color.FromArgb(100, 100, 100);
}
}
private void toggleBMBF_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleAutoReinstall_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleAutoReinstall_Click(object sender, EventArgs e)
{
if (toggleAutoReinstall.Checked)
{
DialogResult dialogResult = FlexibleMessageBox.Show(this,
"WARNING: This enables automatic reinstall when installs fail.\n\n" +
"Some games (less than 5%) don't allow access to their save data, " +
"which can lead to losing your progress.\n\n" +
"However, with this option enabled, you won't have to confirm reinstalls manually " +
"(ideal for queue installations).\n\n" +
"NOTE: If your USB/wireless ADB connection is slow, this may cause " +
"larger APK installations to fail.\n\nEnable anyway?",
"WARNING", MessageBoxButtons.OKCancel);
if (dialogResult == DialogResult.Cancel)
{
toggleAutoReinstall.SetCheckedSilent(false);
}
}
}
private void btnOpenDebug_Click(object sender, EventArgs e)
{
if (File.Exists($"{Environment.CurrentDirectory}\\debuglog.txt"))
{
_ = Process.Start($"{Environment.CurrentDirectory}\\debuglog.txt");
}
}
private void setDownloadDirectory_Click(object sender, EventArgs e)
{
var dialog = new FolderSelectDialog
{
Title = "Select Download Folder",
InitialDirectory = _settings.CustomDownloadDir && Directory.Exists(_settings.DownloadDir)
? _settings.DownloadDir
: Environment.CurrentDirectory
};
if (dialog.Show(this.Handle))
{
_settings.CustomDownloadDir = true;
_settings.DownloadDir = dialog.FileName;
}
}
private void setBackupDirectory_Click(object sender, EventArgs e)
{
var dialog = new FolderSelectDialog
{
Title = "Select Backup Folder",
InitialDirectory = _settings.GetEffectiveBackupDir()
};
if (dialog.Show(this.Handle))
{
_settings.CustomBackupDir = true;
_settings.BackupDir = dialog.FileName;
}
}
private void toggleSingleThread_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void toggleVirtualFilesystem_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
private void openDownloadDirectory_Click(object sender, EventArgs e)
{
string pathToOpen = _settings.CustomDownloadDir ? _settings.DownloadDir : Environment.CurrentDirectory;
MainForm.OpenDirectory(pathToOpen);
}
private void openBackupDirectory_Click(object sender, EventArgs e)
{
string pathToOpen = _settings.GetEffectiveBackupDir();
MainForm.OpenDirectory(pathToOpen);
}
private void bandwidthLimitTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && (e.KeyChar != '.'))
{
e.Handled = true;
}
if ((e.KeyChar == '.') && ((sender as TextBox).Text.IndexOf('.') > -1))
{
e.Handled = true;
}
}
private void toggleProxy_CheckedChanged(object sender, EventArgs e)
{
// Settings saved on form close
}
}
}
using JR.Utils.GUI.Forms;
using System;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class SettingsForm : Form
{
public SettingsForm()
{
InitializeComponent();
}
private void SettingsForm_Load(object sender, EventArgs e)
{
this.CenterToParent();
intSettings();
intToolTips();
}
private void intSettings()
{
checkForUpdatesCheckBox.Checked = Properties.Settings.Default.checkForUpdates;
enableMessageBoxesCheckBox.Checked = Properties.Settings.Default.enableMessageBoxes;
deleteAfterInstallCheckBox.Checked = Properties.Settings.Default.deleteAllAfterInstall;
updateConfigCheckBox.Checked = Properties.Settings.Default.autoUpdateConfig;
userJsonOnGameInstall.Checked = Properties.Settings.Default.userJsonOnGameInstall;
resignGamesCheckbox.Checked = Properties.Settings.Default.ResignAPKs;
if (Properties.Settings.Default.BandwithLimit.Length>1)
{
BandwithTextbox.Text = Properties.Settings.Default.BandwithLimit.Remove(Properties.Settings.Default.BandwithLimit.Length - 1);
BandwithComboBox.Text = Properties.Settings.Default.BandwithLimit[Properties.Settings.Default.BandwithLimit.Length-1].ToString();
}
}
void intToolTips()
{
ToolTip checkForUpdatesToolTip = new ToolTip();
checkForUpdatesToolTip.SetToolTip(this.checkForUpdatesCheckBox, "If this is checked, the software will check for available updates");
ToolTip enableMessageBoxesToolTip = new ToolTip();
enableMessageBoxesToolTip.SetToolTip(this.enableMessageBoxesCheckBox, "If this is checked, the software will display message boxes after every completed task");
ToolTip deleteAfterInstallToolTip = new ToolTip();
deleteAfterInstallToolTip.SetToolTip(this.deleteAfterInstallCheckBox, "If this is checked, the software will delete all game files after downloading and installing a game from a remote server");
}
private void applyButton_Click(object sender, EventArgs e)
{
if (BandwithTextbox.Text.Length > 0 && BandwithTextbox.Text != "0")
if (BandwithComboBox.SelectedIndex == -1)
{
FlexibleMessageBox.Show("You need to select something from the combobox");
return;
}
else
Properties.Settings.Default.BandwithLimit = $"{BandwithTextbox.Text.Replace(" ", "")}{BandwithComboBox.Text}";
else
Properties.Settings.Default.BandwithLimit = "";
Properties.Settings.Default.Save();
}
private void SettingsForm_FormClosing(object sender, FormClosingEventArgs e)
{
}
private void checkForUpdatesCheckBox_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.checkForUpdates = checkForUpdatesCheckBox.Checked;
}
private void enableMessageBoxesCheckBox_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.enableMessageBoxes = enableMessageBoxesCheckBox.Checked;
}
private void resetSettingsButton_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Reset();
intSettings();
}
private void deleteAfterInstallCheckBox_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.deleteAllAfterInstall = deleteAfterInstallCheckBox.Checked;
}
private void updateConfigCheckBox_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.autoUpdateConfig = updateConfigCheckBox.Checked;
}
private void userJsonOnGameInstall_CheckedChanged(object sender, EventArgs e)
{
Properties.Settings.Default.userJsonOnGameInstall = userJsonOnGameInstall.Checked;
}
private void resignGamesCheckbox_CheckedChanged(object sender, EventArgs e)
{
if (resignGamesCheckbox.Checked && Spoofer.spoofer.HasDependencies())
resignGamesCheckbox.Checked = true;
else if (resignGamesCheckbox.Checked)
{
MessageBox.Show("You are missing dependencies (install apktool aapt and jarsigner) and then restart the sideloader");
resignGamesCheckbox.Checked = false;
}
Properties.Settings.Default.ResignAPKs = resignGamesCheckbox.Checked;
}
}
}

View File

@@ -117,13 +117,4 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="downloadDirectorySetter.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="backupDirectorySetter.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>186, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>25</value>
</metadata>
</root>

Binary file not shown.

View File

@@ -1,272 +1,217 @@
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.Threading.Tasks;
using System.Windows.Forms;
namespace AndroidSideloader
{
internal class Sideloader
{
private static readonly SettingsManager settings = SettingsManager.Instance;
public static string TempFolder = Path.Combine(Environment.CurrentDirectory, "temp");
public static string CrashLogPath = "crashlog.txt";
//push user.json to device (required for some devices like oculus quest)
public static void PushUserJsons()
{
foreach (string userJson in UsernameForm.userJsons)
{
UsernameForm.createUserJsonByName(Utilities.GeneralUtilities.randomString(16), userJson);
_ = ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{userJson}\" " + " /sdcard/");
File.Delete(userJson);
}
}
//List of all installed package names from connected device
//public static List<string> InstalledPackageNames = new List<string>(); //Remove folder from device
public static ProcessOutput RemoveFolder(string path)
{
if (path == "/sdcard/Android/obb/" || path == "sdcard/Android/data/")
{
return null;
}
return ADB.RunAdbCommandToString($"shell rm -r \"{path}\"");
}
public static ProcessOutput RemoveFile(string path)
{
return ADB.RunAdbCommandToString($"shell rm -f \"{path}\"");
}
//For games that require manual install, like having another folder that isnt an obb
public static ProcessOutput RunADBCommandsFromFile(string path)
{
ProcessOutput output = new ProcessOutput();
string[] commands = File.ReadAllLines(path);
string currfolder = Path.GetDirectoryName(path);
string[] zipz = Directory.GetFiles(currfolder, "*.7z", SearchOption.AllDirectories);
foreach (string zip in zipz)
{
Utilities.Zip.ExtractFile($"{zip}", currfolder);
}
foreach (string cmd in commands)
{
if (cmd.StartsWith("adb"))
{
string replacement = "";
string pattern = "adb";
replacement = ADB.DeviceID.Length > 1
? $"{settings.ADBPath} -s {ADB.DeviceID}"
: $"{settings.ADBPath}";
Regex rgx = new Regex(pattern);
string result = rgx.Replace(cmd, replacement);
Program.form.changeTitle($"Running {result}");
_ = Logger.Log($"Logging command: {result} from file: {path}");
output += ADB.RunAdbCommandToStringWOADB(result, path);
if (output.Error.Contains("mkdir"))
{
output.Error = "";
}
if (output.Output.Contains("reserved"))
{
output.Output = "";
}
}
}
output.Output += "Custom install successful!";
return output;
}
//Recursive sideload any apk file
public static ProcessOutput RecursiveOutput = new ProcessOutput();
public static async Task RecursiveSideloadAsync(
string FolderPath,
Action<float, TimeSpan?> progressCallback = null,
Action<string> statusCallback = null)
{
try
{
foreach (string f in Directory.GetFiles(FolderPath))
{
if (Path.GetExtension(f) == ".apk")
{
string gameName = Path.GetFileNameWithoutExtension(f);
statusCallback?.Invoke(gameName);
RecursiveOutput += await ADB.SideloadWithProgressAsync(f, progressCallback, statusCallback, "", gameName);
}
}
foreach (string d in Directory.GetDirectories(FolderPath))
{
await RecursiveSideloadAsync(d, progressCallback, statusCallback);
}
}
catch (Exception ex) { _ = Logger.Log(ex.Message, LogLevel.ERROR); }
}
//Recursive copy any obb folder
public static async Task RecursiveCopyOBBAsync(
string FolderPath,
Action<float, TimeSpan?> progressCallback = null,
Action<string> statusCallback = null)
{
try
{
foreach (string d in Directory.GetDirectories(FolderPath))
{
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); }
}
// Removes the game package and its OBB + Data Folders.
public static ProcessOutput UninstallGame(string packagename)
{
ProcessOutput output = ADB.UninstallPackage(packagename);
Program.form.changeTitle("");
_ = Sideloader.RemoveFolder("/sdcard/Android/obb/" + packagename);
_ = Sideloader.RemoveFolder("/sdcard/Android/data/" + packagename);
return output;
}
public static void BackupGame(string packagename)
{
MainForm.backupFolder = settings.GetEffectiveBackupDir();
if (!Directory.Exists(MainForm.backupFolder))
{
_ = Directory.CreateDirectory(MainForm.backupFolder);
}
Program.form.changeTitle($"Attempting to backup any savedata to {MainForm.backupFolder}\\Rookie Backups...");
_ = new ProcessOutput("", "");
string date_str = DateTime.Today.ToString("yyyy.MM.dd");
string CurrBackups = Path.Combine(MainForm.backupFolder, date_str);
if (!Directory.Exists(CurrBackups))
{
_ = Directory.CreateDirectory(CurrBackups);
}
_ = ADB.RunAdbCommandToString($"pull \"/sdcard/Android/data/{packagename}\" \"{CurrBackups}\"");
}
public static ProcessOutput DeleteFile(string GameName)
{
ProcessOutput output = new ProcessOutput("", "");
string packageName = Sideloader.gameNameToPackageName(GameName);
DialogResult dialogResult = FlexibleMessageBox.Show(Program.form, $"Are you sure you want to uninstall custom QU settings for {packageName}? this CANNOT be undone!", "WARNING!", MessageBoxButtons.YesNo);
if (dialogResult != DialogResult.Yes)
{
return output;
}
output = Sideloader.RemoveFile($"/sdcard/Android/data/{packageName}/private/Config.Json");
return output;
}
//Extracts apk from device, saves it by package name to sideloader folder
public static ProcessOutput getApk(string GameName)
{
_ = new ProcessOutput("", "");
string packageName = Sideloader.gameNameToPackageName(GameName);
ProcessOutput output = ADB.RunAdbCommandToString("shell pm path " + packageName);
string apkPath = output.Output; //Get apk
apkPath = apkPath.Remove(apkPath.Length - 1);
apkPath = apkPath.Remove(0, 8); //remove package:
apkPath = apkPath.Remove(apkPath.Length - 1);
if (File.Exists($"{settings.ADBFolder}\\base.apk"))
{
File.Delete($"{settings.ADBFolder}\\base.apk");
}
if (File.Exists($"{settings.MainDir}\\{packageName}\\{packageName}.apk"))
{
File.Delete($"{settings.MainDir}\\{packageName}\\{packageName}.apk");
}
output += ADB.RunAdbCommandToString("pull " + apkPath); //pull apk
if (Directory.Exists($"{settings.MainDir}\\{packageName}"))
{
FileSystemUtilities.TryDeleteDirectory($"{settings.MainDir}\\{packageName}");
}
_ = Directory.CreateDirectory($"{settings.MainDir}\\{packageName}");
File.Move($"{settings.ADBFolder}\\base.apk", $"{settings.MainDir}\\{packageName}\\{packageName}.apk");
return output;
}
public static string gameNameToPackageName(string gameName)
{
foreach (string[] game in SideloaderRCLONE.games)
{
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]) || gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
return game[SideloaderRCLONE.PackageNameIndex];
}
return gameName;
}
public static string gameNameToVersionCode(string gameName)
{
foreach (string[] game in SideloaderRCLONE.games)
{
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]) || gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
return game[SideloaderRCLONE.VersionCodeIndex];
}
return gameName;
}
public static string PackageNametoGameName(string packageName)
{
foreach (string[] game in SideloaderRCLONE.games)
{
if (packageName.Equals(game[SideloaderRCLONE.PackageNameIndex]))
return game[SideloaderRCLONE.ReleaseNameIndex];
}
return packageName;
}
public static string gameNameToSimpleName(string gameName)
{
foreach (string[] game in SideloaderRCLONE.games)
{
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]) || gameName.Equals(game[SideloaderRCLONE.ReleaseNameIndex]))
return game[SideloaderRCLONE.GameNameIndex];
}
return gameName;
}
public static string PackageNameToSimpleName(string packageName)
{
foreach (string[] game in SideloaderRCLONE.games)
{
if (packageName.Contains(game[SideloaderRCLONE.PackageNameIndex]))
return game[SideloaderRCLONE.GameNameIndex];
}
return packageName;
}
}
}
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using System.Net;
using System.Windows.Forms;
using JR.Utils.GUI.Forms;
namespace AndroidSideloader
{
class Sideloader
{
public static string CrashLogPath = "crashlog.txt";
public static string SpooferWarning = @"Please make sure you have installed:
- APKTool
- Java JDK
- aapt
And all of them added to PATH, without ANY of them, the spoofer won't work!";
public static void PushUserJsons()
{
ADB.WakeDevice();
foreach (var userJson in UsernameForm.userJsons)
{
UsernameForm.createUserJsonByName(Utilities.GeneralUtilities.randomString(16), userJson);
ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{userJson}\" " + " /sdcard/");
File.Delete(userJson);
}
}
public static List<string> InstalledPackageNames = new List<string>();
public static ProcessOutput RemoveFolder(string path)
{
ADB.WakeDevice();
return ADB.RunAdbCommandToString($"shell rm -r {path}");
}
public static ProcessOutput RunADBCommandsFromFile(string path, string RunFromPath)
{
ADB.WakeDevice();
ProcessOutput output = new ProcessOutput("","");
var commands = File.ReadAllLines(path);
foreach (string cmd in commands)
{
if (cmd.StartsWith("adb"))
{
var regex = new Regex(Regex.Escape("adb"));
var command = regex.Replace(cmd, $"\"{ADB.adbFilePath}\"", 1);
Logger.Log($"Logging command: {command} from file: {path}");
if (ADB.DeviceID.Length > 1)
command = $" -s {ADB.DeviceID} {command}";
output += Utilities.GeneralUtilities.startProcess("cmd.exe", RunFromPath, command);
}
}
return output;
}
public static ProcessOutput RecursiveOutput = new ProcessOutput("","");
public static void RecursiveSideload(string FolderPath)
{
try
{
foreach (string f in Directory.GetFiles(FolderPath))
{
if (Path.GetExtension(f)==".apk")
RecursiveOutput += ADB.Sideload(f);
}
foreach (string d in Directory.GetDirectories(FolderPath))
{
RecursiveSideload(d);
}
}
catch (Exception ex) { Logger.Log(ex.Message); }
}
public static void RecursiveCopyOBB(string FolderPath)
{
try
{
foreach (string f in Directory.GetFiles(FolderPath))
{
RecursiveOutput += ADB.CopyOBB(f);
}
foreach (string d in Directory.GetDirectories(FolderPath))
{
RecursiveCopyOBB(d);
}
}
catch (Exception ex) { Logger.Log(ex.Message); }
}
public static ProcessOutput UninstallGame(string GameName)
{
ADB.WakeDevice();
ProcessOutput output = new ProcessOutput("", "");
string packageName = Sideloader.gameNameToPackageName(GameName);
DialogResult dialogResult = FlexibleMessageBox.Show($"Are you sure you want to uninstall {packageName}? this CANNOT be undone!", "WARNING!", MessageBoxButtons.YesNo);
if (dialogResult != DialogResult.Yes)
return output;
output = ADB.UninstallPackage(packageName);
Sideloader.RemoveFolder("/sdcard/Android/obb/" + packageName);
Sideloader.RemoveFolder("/sdcard/Android/data/" + packageName);
return output;
}
public static ProcessOutput getApk(string GameName)
{
ADB.WakeDevice();
ProcessOutput output = new ProcessOutput("", "");
string packageName = Sideloader.gameNameToPackageName(GameName);
output = ADB.RunAdbCommandToString("shell pm path " + packageName);
string apkPath = output.Output; //Get apk
apkPath = apkPath.Remove(apkPath.Length - 1);
apkPath = apkPath.Remove(0, 8); //remove package:
apkPath = apkPath.Remove(apkPath.Length - 1);
output += ADB.RunAdbCommandToString("pull " + apkPath); //pull apk
string currApkPath = apkPath;
while (currApkPath.Contains("/"))
currApkPath = currApkPath.Substring(currApkPath.IndexOf("/") + 1);
if (File.Exists(Environment.CurrentDirectory + "\\" + packageName + ".apk"))
File.Delete(Environment.CurrentDirectory + "\\" + packageName + ".apk");
File.Move(Environment.CurrentDirectory + "\\adb\\" + currApkPath, Environment.CurrentDirectory + "\\" + packageName + ".apk");
return output;
}
public static string gameNameToPackageName(string gameName)
{
foreach (string[] game in SideloaderRCLONE.games)
{
if (gameName.Equals(game[SideloaderRCLONE.GameNameIndex]))
return game[SideloaderRCLONE.PackageNameIndex];
}
return gameName;
}
public static void downloadFiles()
{
using (var client = new WebClient())
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
if (!File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\warning.png"))
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/secret", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\warning.png");
if (!File.Exists("Sideloader Launcher.exe"))
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/Sideloader%20Launcher.exe", "Sideloader Launcher.exe");
if (!Directory.Exists(ADB.adbFolderPath)) //if there is no adb folder, download and extract
{
try
{
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/adb.7z", "adb.7z");
Utilities.Zip.ExtractFile(Environment.CurrentDirectory + "\\adb.7z", Environment.CurrentDirectory);
File.Delete("adb.7z");
}
catch
{
}
}
if (!Directory.Exists(Environment.CurrentDirectory + "\\rclone"))
{
string url;
if (Environment.Is64BitOperatingSystem)
url = "https://downloads.rclone.org/v1.53.1/rclone-v1.53.1-windows-amd64.zip";
else
url = "https://downloads.rclone.org/v1.53.1/rclone-v1.53.1-windows-386.zip";
client.DownloadFile(url, "rclone.zip");
Utilities.Zip.ExtractFile(Environment.CurrentDirectory + "\\rclone.zip", Environment.CurrentDirectory);
File.Delete("rclone.zip");
string[] folders = Directory.GetDirectories(Environment.CurrentDirectory);
foreach (string folder in folders)
{
if (folder.Contains("rclone"))
{
Directory.Move(folder, "rclone");
break;
}
}
}
}
}
}
}

View File

@@ -1,333 +0,0 @@
using AndroidSideloader.Utilities;
using JR.Utils.GUI.Forms;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AndroidSideloader
{
internal class GetDependencies
{
public static void updatePublicConfig()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
_ = Logger.Log("Attempting to update public config from main.");
string configUrl = "https://raw.githubusercontent.com/vrpyou/quest/main/vrp-public.json";
string fallbackUrl = "https://vrpirates.wiki/downloads/vrp-public.json";
try
{
string resultString;
// Try fetching raw JSON data from the provided link
HttpWebRequest getUrl = DnsHelper.CreateWebRequest(configUrl);
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
{
resultString = responseReader.ReadToEnd();
_ = Logger.Log($"Retrieved updated config from main: {configUrl}.");
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "vrp-public.json"), resultString);
_ = Logger.Log("Public config updated successfully from main.");
}
}
catch (Exception mainException)
{
_ = Logger.Log($"Failed to update public config from main: {mainException.Message}, trying fallback.", LogLevel.ERROR);
try
{
HttpWebRequest getUrl = DnsHelper.CreateWebRequest(fallbackUrl);
using (StreamReader responseReader = new StreamReader(getUrl.GetResponse().GetResponseStream()))
{
string resultString = responseReader.ReadToEnd();
_ = Logger.Log($"Retrieved updated config from fallback: {fallbackUrl}.");
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "vrp-public.json"), resultString);
_ = Logger.Log("Public config updated successfully from fallback.");
}
}
catch (Exception fallbackException)
{
_ = Logger.Log($"Failed to update public config from fallback: {fallbackException.Message}.", LogLevel.ERROR);
}
}
}
// Download required dependencies
public static void downloadFiles()
{
// Initialize DNS helper early to detect and configure fallback if needed
DnsHelper.Initialize();
WebClient client = new WebClient();
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var currentAccessedWebsite = "";
try
{
if (!File.Exists("Sideloader Launcher.exe"))
{
currentAccessedWebsite = "github";
_ = Logger.Log($"Missing 'Sideloader Launcher.exe'. Attempting to download from {currentAccessedWebsite}");
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/Sideloader%20Launcher.exe", "Sideloader Launcher.exe");
_ = Logger.Log($"'Sideloader Launcher.exe' download successful");
}
if (!File.Exists("Rookie Offline.cmd"))
{
currentAccessedWebsite = "github";
_ = Logger.Log($"Missing 'Rookie Offline.cmd'. Attempting to download from {currentAccessedWebsite}");
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/Rookie%20Offline.cmd", "Rookie Offline.cmd");
_ = Logger.Log($"'Rookie Offline.cmd' download successful");
}
if (!File.Exists("CleanupInstall.cmd"))
{
currentAccessedWebsite = "github";
_ = Logger.Log($"Missing 'CleanupInstall.cmd'. Attempting to download from {currentAccessedWebsite}");
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/CleanupInstall.cmd", "CleanupInstall.cmd");
_ = Logger.Log($"'CleanupInstall.cmd' download successful");
}
if (!File.Exists("AddDefenderExceptions.ps1"))
{
currentAccessedWebsite = "github";
_ = Logger.Log($"Missing 'AddDefenderExceptions.ps1'. Attempting to download from {currentAccessedWebsite}");
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/AddDefenderExceptions.ps1", "AddDefenderExceptions.ps1");
_ = Logger.Log($"'AddDefenderExceptions.ps1' download successful");
}
}
catch (Exception ex)
{
_ = FlexibleMessageBox.Show(Program.form, $"You are unable to access raw.githubusercontent.com with the Exception:\n{ex.Message}\n\nSome files may be missing (Offline/Cleanup Script, Launcher)");
}
string adbPath = Path.Combine(Environment.CurrentDirectory, "platform-tools", "adb.exe");
string platformToolsDir = Path.Combine(Environment.CurrentDirectory, "platform-tools");
try
{
if (!File.Exists(adbPath)) //if adb is not updated, download and auto extract
{
if (!Directory.Exists(platformToolsDir))
{
_ = Directory.CreateDirectory(platformToolsDir);
}
currentAccessedWebsite = "github";
_ = Logger.Log($"Missing adb within {platformToolsDir}. Attempting to download from {currentAccessedWebsite}");
DownloadFileWithDnsFallback(client, "https://github.com/VRPirates/rookie/raw/master/dependencies.7z", "dependencies.7z");
Utilities.Zip.ExtractFile(Path.Combine(Environment.CurrentDirectory, "dependencies.7z"), platformToolsDir);
File.Delete("dependencies.7z");
_ = Logger.Log($"adb download successful");
}
}
catch (Exception ex)
{
_ = FlexibleMessageBox.Show(Program.form, $"You are unable to access raw.githubusercontent.com page with the Exception:\n{ex.Message}\n\nSome files may be missing (ADB)");
_ = FlexibleMessageBox.Show(Program.form, "ADB was unable to be downloaded\nRookie will now close.");
Application.Exit();
}
string wantedRcloneVersion = "1.72.1";
bool rcloneSuccess = false;
rcloneSuccess = downloadRclone(wantedRcloneVersion, false);
if (!rcloneSuccess)
{
rcloneSuccess = downloadRclone(wantedRcloneVersion, true);
}
if (!rcloneSuccess)
{
_ = Logger.Log($"Unable to download rclone", LogLevel.ERROR);
_ = FlexibleMessageBox.Show(Program.form, "Rclone was unable to be downloaded\nRookie will now close, please use Offline Mode for manual sideloading if needed");
Application.Exit();
}
// Download WebView2 runtime if needed
downloadWebView2Runtime();
}
// Downloads a file using the DNS fallback proxy if active
public static void DownloadFileWithDnsFallback(WebClient client, string url, string localPath)
{
try
{
// Use DNS fallback proxy if active
if (DnsHelper.UseFallbackDns && !string.IsNullOrEmpty(DnsHelper.ProxyUrl))
{
client.Proxy = new WebProxy(DnsHelper.ProxyUrl);
}
client.DownloadFile(url, localPath);
}
catch (Exception ex)
{
_ = Logger.Log($"Download failed for {url}: {ex.Message}", LogLevel.ERROR);
throw;
}
finally
{
// Reset proxy to avoid affecting other operations
client.Proxy = null;
}
}
// Overload that creates its own WebClient for convenience
public static void DownloadFileWithDnsFallback(string url, string localPath)
{
using (var client = new WebClient())
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
DownloadFileWithDnsFallback(client, url, localPath);
}
}
// Downloads WebView2 runtime if not present
private static void downloadWebView2Runtime()
{
string runtimesPath = Path.Combine(Environment.CurrentDirectory, "runtimes");
string webView2LoaderArm64 = Path.Combine(runtimesPath, "win-arm64", "native", "WebView2Loader.dll");
string webView2LoaderX86 = Path.Combine(runtimesPath, "win-x86", "native", "WebView2Loader.dll");
string webView2LoaderX64 = Path.Combine(runtimesPath, "win-x64", "native", "WebView2Loader.dll");
bool runtimeExists = File.Exists(webView2LoaderX86) || File.Exists(webView2LoaderX64) || File.Exists(webView2LoaderArm64);
if (!runtimeExists)
{
try
{
_ = Logger.Log("Missing WebView2 runtime. Attempting to download...");
string archivePath = Path.Combine(Environment.CurrentDirectory, "runtimes.7z");
DownloadFileWithDnsFallback("https://vrpirates.wiki/downloads/runtimes.7z", archivePath);
_ = Logger.Log("Extracting WebView2 runtime...");
Utilities.Zip.ExtractFile(archivePath, Environment.CurrentDirectory);
File.Delete(archivePath);
_ = Logger.Log("WebView2 runtime download successful");
}
catch (Exception ex)
{
_ = Logger.Log($"Failed to download WebView2 runtime: {ex.Message}", LogLevel.ERROR);
// Don't show message box here - let CreateEnvironment handle the UI feedback
}
}
}
public static bool downloadRclone(string wantedRcloneVersion, bool useFallback = false)
{
try
{
bool updateRclone = false;
string currentRcloneVersion = "0.0.0";
WebClient client = new WebClient();
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
_ = Logger.Log($"Checking for Local rclone...");
string dirRclone = Path.Combine(Environment.CurrentDirectory, "rclone");
string pathToRclone = Path.Combine(dirRclone, "rclone.exe");
if (File.Exists(pathToRclone))
{
var versionInfo = FileVersionInfo.GetVersionInfo(pathToRclone);
currentRcloneVersion = versionInfo.ProductVersion;
Logger.Log($"Current RCLONE Version {currentRcloneVersion}");
if (!MainForm.noRcloneUpdating)
{
if (currentRcloneVersion != wantedRcloneVersion)
{
updateRclone = true;
_ = Logger.Log($"RCLONE Version does not match ({currentRcloneVersion})! Downloading required version ({wantedRcloneVersion})");
}
}
}
else
{
updateRclone = true;
_ = Logger.Log($"RCLONE exe does not exist, attempting to download");
}
if (!Directory.Exists(dirRclone))
{
updateRclone = true;
_ = Logger.Log($"Missing RCLONE Folder, attempting to download");
Directory.CreateDirectory(dirRclone);
}
if (updateRclone == true)
{
// Preserve vrp.download.config if it exists
string configPath = Path.Combine(dirRclone, "vrp.download.config");
string tempConfigPath = Path.Combine(Environment.CurrentDirectory, "vrp.download.config.bak");
bool hasConfig = false;
if (File.Exists(configPath))
{
_ = Logger.Log("Preserving vrp.download.config before update");
File.Copy(configPath, tempConfigPath, true);
hasConfig = true;
}
string architecture = Environment.Is64BitOperatingSystem ? "amd64" : "386";
string url = $"https://downloads.rclone.org/v{wantedRcloneVersion}/rclone-v{wantedRcloneVersion}-windows-{architecture}.zip";
if (useFallback == true)
{
_ = Logger.Log($"Using git fallback for rclone download");
url = $"https://raw.githubusercontent.com/VRPirates/rookie/master/dep/rclone-v{wantedRcloneVersion}-windows-{architecture}.zip";
}
_ = Logger.Log($"Downloading rclone from {url}");
_ = Logger.Log("Begin download rclone");
DownloadFileWithDnsFallback(client, url, "rclone.zip");
_ = Logger.Log("Complete download rclone");
_ = Logger.Log($"Extract {Environment.CurrentDirectory}\\rclone.zip");
Utilities.Zip.ExtractFile(Path.Combine(Environment.CurrentDirectory, "rclone.zip"), Environment.CurrentDirectory);
string dirExtractedRclone = Path.Combine(Environment.CurrentDirectory, $"rclone-v{wantedRcloneVersion}-windows-{architecture}");
File.Delete("rclone.zip");
_ = Logger.Log("rclone extracted. Moving files");
foreach (string file in Directory.GetFiles(dirExtractedRclone))
{
string fileName = Path.GetFileName(file);
string destFile = Path.Combine(dirRclone, fileName);
if (File.Exists(destFile))
{
File.Delete(destFile);
}
File.Move(file, destFile);
}
FileSystemUtilities.TryDeleteDirectory(dirExtractedRclone);
// Restore vrp.download.config if it was backed up
if (hasConfig && File.Exists(tempConfigPath))
{
_ = Logger.Log("Restoring vrp.download.config after update");
File.Move(tempConfigPath, configPath);
}
_ = Logger.Log($"rclone download successful");
}
return true;
}
catch (Exception ex)
{
_ = Logger.Log($"Unable to download rclone: {ex}", LogLevel.ERROR);
return false;
}
}
}
}

View File

@@ -1,11 +1,17 @@
namespace AndroidSideloader
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AndroidSideloader
{
public class ProcessOutput
{
public string Output;
public string Error;
public ProcessOutput(string output = "", string error = "")
public ProcessOutput(string output, string error)
{
Output = output;
Error = error;

View File

@@ -1,27 +1,26 @@
using AndroidSideloader.Utilities;
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace AndroidSideloader
{
internal class SideloaderRCLONE
class SideloaderRCLONE
{
public static List<string> RemotesList = new List<string>();
public static string RcloneGamesFolder = "Quest Games";
//This shit sucks but i'll switch to programatically adding indexes from the gamelist txt sometimes maybe
public static int GameNameIndex = 0;
public static int ReleaseNameIndex = 1;
public static int PackageNameIndex = 2;
public static int VersionCodeIndex = 3;
public static int ReleaseAPKPathIndex = 4;
public static int ReleaseAPKPathIndex = 2;
public static int PackageNameIndex = 3;
public static int VersionCodeIndex = 4;
public static int VersionNameIndex = 5;
public static int DownloadsIndex = 6;
public static int InstalledVersion = 7;
public static List<string> gameProperties = new List<string>();
/* Game Name
@@ -33,300 +32,105 @@ namespace AndroidSideloader
*/
public static List<string[]> games = new List<string[]>();
public static string Nouns = Path.Combine(Environment.CurrentDirectory, "nouns");
public static string ThumbnailsFolder = Path.Combine(Environment.CurrentDirectory, "thumbnails");
public static string NotesFolder = Path.Combine(Environment.CurrentDirectory, "notes");
public static void UpdateNouns(string remote)
{
_ = Logger.Log($"Updating Nouns");
_ = RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/nouns\" \"{Nouns}\"");
}
public static string ThumbnailsFolder = Environment.CurrentDirectory + "\\thumbnails";
public static string NotesFolder = Environment.CurrentDirectory + "\\notes";
public static void UpdateGamePhotos(string remote)
{
_ = Logger.Log($"Updating Thumbnails");
_ = RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/thumbnails\" \"{ThumbnailsFolder}\" --transfers 10");
RCLONE.runRcloneCommand($"sync \"{remote}:{RcloneGamesFolder}/.meta/thumbnails\" \"{ThumbnailsFolder}\"");
}
public static void UpdateGameNotes(string remote)
{
_ = Logger.Log($"Updating Game Notes");
_ = RCLONE.runRcloneCommand_DownloadConfig($"sync \"{remote}:{RcloneGamesFolder}/.meta/notes\" \"{NotesFolder}\"");
RCLONE.runRcloneCommand($"sync \"{remote}:{RcloneGamesFolder}/.meta/notes\" \"{NotesFolder}\"");
}
public static void UpdateMetadataFromPublic()
public static void RefreshRemotes()
{
_ = Logger.Log($"Downloading Metadata");
string rclonecommand =
$"sync \":http:/meta.7z\" \"{Environment.CurrentDirectory}\"";
_ = RCLONE.runRcloneCommand_PublicConfig(rclonecommand);
}
RemotesList.Clear();
var remotes = RCLONE.runRcloneCommand("listremotes").Output.Split('\n');
public static void ProcessMetadataFromPublic()
{
try
Logger.Log("Loaded following remotes: ");
foreach (string r in remotes)
{
var sw = Stopwatch.StartNew();
string currentDir = Environment.CurrentDirectory;
string metaRoot = Path.Combine(currentDir, "meta");
string metaArchive = Path.Combine(currentDir, "meta.7z");
string metaDotMeta = Path.Combine(metaRoot, ".meta");
// Check if archive exists and is newer than existing metadata
if (!File.Exists(metaArchive))
if (r.Length > 1)
{
Logger.Log("meta.7z not found, skipping extraction", LogLevel.WARNING);
return;
}
// Skip extraction if metadata is already up-to-date (based on file timestamps)
string gameListPath = Path.Combine(metaRoot, "VRP-GameList.txt");
if (File.Exists(gameListPath))
{
var archiveTime = File.GetLastWriteTimeUtc(metaArchive);
var gameListTime = File.GetLastWriteTimeUtc(gameListPath);
// If game list is newer than archive, skip extraction
if (gameListTime > archiveTime && games.Count > 0)
var remote = r.Remove(r.Length - 1);
if (remote.Contains("mirror"))
{
Logger.Log($"Metadata already up-to-date, skipping extraction");
return;
Logger.Log(remote);
RemotesList.Add(remote);
}
}
_ = Logger.Log($"Extracting Metadata");
Zip.ExtractFile(metaArchive, metaRoot, MainForm.PublicConfigFile.Password);
Logger.Log($"Extraction completed in {sw.ElapsedMilliseconds}ms");
sw.Restart();
_ = Logger.Log($"Updating Metadata");
// Use Parallel.Invoke for independent directory operations
System.Threading.Tasks.Parallel.Invoke(
() => SafeDeleteDirectory(Nouns),
() => SafeDeleteDirectory(ThumbnailsFolder),
() => SafeDeleteDirectory(NotesFolder)
);
Logger.Log($"Directory cleanup in {sw.ElapsedMilliseconds}ms");
sw.Restart();
// Move directories
MoveIfExists(Path.Combine(metaDotMeta, "nouns"), Nouns);
MoveIfExists(Path.Combine(metaDotMeta, "thumbnails"), ThumbnailsFolder);
MoveIfExists(Path.Combine(metaDotMeta, "notes"), NotesFolder);
Logger.Log($"Directory moves in {sw.ElapsedMilliseconds}ms");
sw.Restart();
_ = Logger.Log($"Initializing Games List");
gameListPath = Path.Combine(metaRoot, "VRP-GameList.txt");
if (File.Exists(gameListPath))
{
// Read all lines at once - faster for files that fit in memory
var lines = File.ReadAllLines(gameListPath);
var newGames = new List<string[]>(lines.Length);
for (int i = 1; i < lines.Length; i++) // Skip header
{
var line = lines[i];
if (string.IsNullOrWhiteSpace(line))
continue;
var splitGame = line.Split(';');
if (splitGame.Length > 1)
{
newGames.Add(splitGame);
}
}
// Atomic swap
games.Clear();
games.AddRange(newGames);
Logger.Log($"Parsed {games.Count} games in {sw.ElapsedMilliseconds}ms");
}
else
{
_ = Logger.Log("VRP-GameList.txt not found in extracted metadata.", LogLevel.WARNING);
}
SafeDeleteDirectory(metaRoot);
}
catch (Exception e)
{
_ = Logger.Log(e.Message);
_ = Logger.Log(e.StackTrace);
}
}
public static void initGames(string remote)
{
_ = Logger.Log($"Initializing Games List");
gameProperties.Clear();
games.Clear();
string tempGameList = RCLONE.runRcloneCommand($"cat \"{remote}:{RcloneGamesFolder}/GameList.txt\"").Output;
//File.WriteAllText("GamesList.txt", tempGameList);
string gamePropertiesLine = Utilities.StringUtilities.RemoveEverythingAfterFirst(tempGameList, "\n");
// Fetch once, then process as lines
string tempGameList = RCLONE.runRcloneCommand_DownloadConfig($"cat \"{remote}:{RcloneGamesFolder}/VRP-GameList.txt\"").Output;
if (MainForm.debugMode)
foreach (string gameProperty in gamePropertiesLine.Split(';'))
{
// Avoid redundant disk I/O: write only if non-empty
if (!string.IsNullOrEmpty(tempGameList))
{
File.WriteAllText("VRP-GamesList.txt", tempGameList);
}
gameProperties.Add(gameProperty);
}
if (!string.IsNullOrEmpty(tempGameList))
tempGameList = Utilities.StringUtilities.RemoveEverythingBeforeFirst(tempGameList, "\n");
foreach (string game in tempGameList.Split('\n'))
{
bool isFirstLine = true;
foreach (var line in SplitLines(tempGameList))
{
if (isFirstLine)
{
isFirstLine = false; // skip header
continue;
}
if (game.Length > 1)
games.Add(game.Split(';'));
}
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
var splitGame = line.Split(new[] { ';' }, StringSplitOptions.None);
if (splitGame.Length > 1)
{
games.Add(splitGame);
}
}
//Output
Console.WriteLine("Headers:");
foreach (string s in gameProperties)
{
Console.WriteLine($"gameProperty: {s}");
}
Console.WriteLine("Games");
foreach (string[] s in games)
{
string output = "";
for (int i = 0; i < gameProperties.Count; i++)
output += s[i] + " ";
Console.WriteLine(output);
}
}
public static void updateUploadConfig()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
_ = Logger.Log($"Attempting to Update Upload Config");
try
{
string configUrl = "https://vrpirates.wiki/downloads/vrp.upload.config";
// Use DnsHelper for fallback DNS support
var getUrl = DnsHelper.CreateWebRequest(configUrl);
using (var response = getUrl.GetResponse())
using (var stream = response.GetResponseStream())
using (var responseReader = new StreamReader(stream))
{
string resultString = responseReader.ReadToEnd();
_ = Logger.Log($"Retrieved updated config from: {configUrl}");
// Avoid multiple combines; write once
string uploadConfigPath = Path.Combine(Environment.CurrentDirectory, "rclone", "vrp.upload.config");
File.WriteAllText(uploadConfigPath, resultString);
_ = Logger.Log("Upload config updated successfully.");
}
}
catch (Exception e)
{
_ = Logger.Log($"Failed to update Upload config: {e.Message}", LogLevel.ERROR);
}
}
// Fast directory delete using Windows cmd - faster than .NET's Directory.Delete
// for large directories with many files (e.g., thumbnails folder with 1000+ images)
private static void SafeDeleteDirectory(string path)
{
// Avoid exceptions when directory is missing
if (!Directory.Exists(path))
return;
try
{
// Use Windows rd command which is ~10x faster than .NET's recursive delete
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/c rd /s /q \"{path}\"",
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
using (var process = Process.Start(psi))
{
// Wait with timeout to prevent hanging
if (!process.WaitForExit(30000)) // 30 second timeout
{
try { process.Kill(); } catch { }
Logger.Log($"Directory delete timed out for: {path}", LogLevel.WARNING);
// Fallback to .NET delete
FallbackDelete(path);
}
else if (process.ExitCode != 0 && Directory.Exists(path))
{
// Command failed, try fallback
FallbackDelete(path);
}
}
}
catch (Exception ex)
{
Logger.Log($"Fast delete failed for {path}: {ex.Message}", LogLevel.WARNING);
// Fallback to standard .NET delete
FallbackDelete(path);
}
}
// Fallback delete method using standard .NET
private static void FallbackDelete(string path)
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
public static long GetFolderSize(string FolderName, string remote)
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
{
try
{
if (Directory.Exists(path))
{
FileSystemUtilities.TryDeleteDirectory(path);
}
}
catch (Exception ex)
{
Logger.Log($"Fallback delete also failed for {path}: {ex.Message}", LogLevel.ERROR);
dynamic results = JsonConvert.DeserializeObject<dynamic>(RCLONE.runRcloneCommand($"size \"{remote}:{RcloneGamesFolder}/{FolderName}\" --json").Output);
long gameSize = results.bytes.ToObject<long>();
return gameSize / 1000000;
}
catch { return 0; }
}
// Move directory only if source exists
private static void MoveIfExists(string sourceDir, string destDir)
public static async Task updateConfig(string remote)
{
if (Directory.Exists(sourceDir))
{
// Ensure destination does not exist to prevent IOException
// Use fast delete method
SafeDeleteDirectory(destDir);
Directory.Move(sourceDir, destDir);
}
else
{
_ = Logger.Log($"Source directory not found: {sourceDir}", LogLevel.WARNING);
}
}
string localHash = "";
try { localHash = File.ReadAllText(Environment.CurrentDirectory + "\\rclone\\hash.txt"); } catch { } //file may not exist
// Efficient, cross-platform line splitting for string buffers
private static IEnumerable<string> SplitLines(string s)
{
// Handle both \r\n and \n without allocating intermediate arrays
using (var reader = new StringReader(s))
string hash = RCLONE.runRcloneCommand($"md5sum \"{remote}:Quest Homebrew/Sideloading Methods/1. Rookie Sideloader - VRP Edition/VRP.download.config\"").Output;
try { hash = hash.Substring(0, hash.LastIndexOf(" ")); } catch { return; } //remove stuff after hash
Debug.WriteLine("The local file hash is " + localHash + " and the current a file hash is " + hash);
if (!string.Equals(localHash, hash))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
RCLONE.runRcloneCommand(string.Format($"copy \"{remote}:Quest Homebrew/Sideloading Methods/1. Rookie Sideloader - VRP Edition/VRP.download.config\" \"{Environment.CurrentDirectory}\\rclone\""));
RCLONE.killRclone();
File.WriteAllText(Environment.CurrentDirectory + "\\rclone\\hash.txt", hash);
}
}
}
}
}

View File

@@ -1,52 +1,17 @@
using AndroidSideloader.Utilities;
using System;
using System.IO;
using System.Management;
using System.Security.Cryptography;
using System.Text;
using System.IO;
namespace AndroidSideloader
{
internal class SideloaderUtilities
class SideloaderUtilities
{
private static readonly SettingsManager settings = SettingsManager.Instance;
public static bool CheckFolderIsObb(string path)
{
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
if (file.EndsWith(".obb") || (Path.GetDirectoryName(file).Contains(".") && !Path.GetDirectoryName(file).Contains("_data")))
{
if (file.EndsWith(".obb"))
return true;
}
}
return false;
}
private static string uuid = null;
public static string UUID()
{
uuid = settings.UUID;
if (string.IsNullOrEmpty(uuid) != true)
{
return uuid;
}
var bytes = new byte[16];
using (var rng = new RNGCryptoServiceProvider())
{
rng.GetBytes(bytes);
}
uuid = BitConverter.ToString(bytes).Replace("-", "");
settings.UUID = uuid;
settings.Save();
return uuid;
}
}
}

118
SpoofForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,118 @@
namespace AndroidSideloader
{
partial class SpoofForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.PackageNameTextBox = new System.Windows.Forms.TextBox();
this.RandomizeButton = new System.Windows.Forms.Button();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.SpoofButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// PackageNameTextBox
//
this.PackageNameTextBox.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
this.PackageNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.PackageNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "TextBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.PackageNameTextBox.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.PackageNameTextBox.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.PackageNameTextBox.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.PackageNameTextBox.Location = new System.Drawing.Point(13, 13);
this.PackageNameTextBox.Name = "PackageNameTextBox";
this.PackageNameTextBox.Size = new System.Drawing.Size(273, 24);
this.PackageNameTextBox.TabIndex = 1;
//
// RandomizeButton
//
this.RandomizeButton.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
this.RandomizeButton.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.RandomizeButton.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.RandomizeButton.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.RandomizeButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.RandomizeButton.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.RandomizeButton.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.RandomizeButton.Location = new System.Drawing.Point(12, 72);
this.RandomizeButton.Name = "RandomizeButton";
this.RandomizeButton.Size = new System.Drawing.Size(110, 42);
this.RandomizeButton.TabIndex = 2;
this.RandomizeButton.Text = "Randomize";
this.RandomizeButton.UseVisualStyleBackColor = false;
this.RandomizeButton.Click += new System.EventHandler(this.RandomizeButton_Click);
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(13, 43);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(273, 23);
this.progressBar1.TabIndex = 3;
//
// SpoofButton
//
this.SpoofButton.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
this.SpoofButton.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.SpoofButton.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.SpoofButton.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.SpoofButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.SpoofButton.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.SpoofButton.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.SpoofButton.Location = new System.Drawing.Point(176, 72);
this.SpoofButton.Name = "SpoofButton";
this.SpoofButton.Size = new System.Drawing.Size(110, 42);
this.SpoofButton.TabIndex = 4;
this.SpoofButton.Text = "Spoof!";
this.SpoofButton.UseVisualStyleBackColor = false;
this.SpoofButton.Click += new System.EventHandler(this.SpoofButton_Click);
//
// SpoofForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
this.ClientSize = new System.Drawing.Size(300, 131);
this.Controls.Add(this.SpoofButton);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.RandomizeButton);
this.Controls.Add(this.PackageNameTextBox);
this.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.MaximumSize = new System.Drawing.Size(316, 170);
this.MinimumSize = new System.Drawing.Size(316, 170);
this.Name = "SpoofForm";
this.Text = "SpoofForm";
this.Load += new System.EventHandler(this.SpoofForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox PackageNameTextBox;
private System.Windows.Forms.Button RandomizeButton;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Button SpoofButton;
}
}

72
SpoofForm.cs Normal file
View File

@@ -0,0 +1,72 @@
using JR.Utils.GUI.Forms;
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Forms;
using Spoofer;
namespace AndroidSideloader
{
public partial class SpoofForm : Form
{
public SpoofForm()
{
InitializeComponent();
}
private async void SpoofButton_Click(object sender, EventArgs e)
{
if (!spoofer.HasDependencies())
{
MessageBox.Show("You are missing the dependencies... Cannot spoof games");
return;
}
string NewPackageName = PackageNameTextBox.Text;
string path;
using (OpenFileDialog openFileDialog = new OpenFileDialog())
{
openFileDialog.Filter = "Android apps (*.apk)|*.apk";
openFileDialog.FilterIndex = 2;
openFileDialog.RestoreDirectory = true;
if (openFileDialog.ShowDialog() == DialogResult.OK)
path = openFileDialog.FileName;
else
return;
}
progressBar1.Style = ProgressBarStyle.Marquee;
string output = "";
Thread t1 = new Thread(() =>
{
spoofer.Init();
output += spoofer.SpoofApk(path, NewPackageName);
});
t1.IsBackground = true;
t1.Start();
while (t1.IsAlive)
await Task.Delay(100);
progressBar1.Style = ProgressBarStyle.Continuous;
if (output.Contains("is not recognized as an internal or external command"))
FlexibleMessageBox.Show(Sideloader.SpooferWarning);
else
FlexibleMessageBox.Show($"App spoofed from {spoofer.originalPackageName} to {NewPackageName}");
}
private void SpoofForm_Load(object sender, EventArgs e)
{
PackageNameTextBox.Text = Utilities.GeneralUtilities.RandomPackageName();
}
private void RandomizeButton_Click(object sender, EventArgs e)
{
PackageNameTextBox.Text = Utilities.GeneralUtilities.RandomPackageName();
}
}
}

View File

@@ -1,120 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

236
ThemeForm.Designer.cs generated Normal file
View File

@@ -0,0 +1,236 @@
namespace AndroidSideloader
{
partial class themeForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.colorDialog1 = new System.Windows.Forms.ColorDialog();
this.button1 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.button5 = new System.Windows.Forms.Button();
this.button7 = new System.Windows.Forms.Button();
this.button8 = new System.Windows.Forms.Button();
this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog();
this.button9 = new System.Windows.Forms.Button();
this.button10 = new System.Windows.Forms.Button();
this.fontDialog1 = new System.Windows.Forms.FontDialog();
this.button3 = new System.Windows.Forms.Button();
this.button11 = new System.Windows.Forms.Button();
this.button12 = new System.Windows.Forms.Button();
this.button13 = new System.Windows.Forms.Button();
this.openThemeDialog = new System.Windows.Forms.OpenFileDialog();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// colorDialog1
//
this.colorDialog1.AnyColor = true;
this.colorDialog1.FullOpen = true;
//
// button1
//
this.button1.Location = new System.Drawing.Point(13, 12);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(128, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Set backgorund color";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button4
//
this.button4.Location = new System.Drawing.Point(13, 125);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(128, 23);
this.button4.TabIndex = 0;
this.button4.Text = "Set button color";
this.button4.UseVisualStyleBackColor = true;
this.button4.Click += new System.EventHandler(this.button4_Click);
//
// button5
//
this.button5.Location = new System.Drawing.Point(13, 181);
this.button5.Name = "button5";
this.button5.Size = new System.Drawing.Size(128, 23);
this.button5.TabIndex = 0;
this.button5.Text = "Set combobox color";
this.button5.UseVisualStyleBackColor = true;
this.button5.Click += new System.EventHandler(this.button5_Click);
//
// button7
//
this.button7.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.button7.Location = new System.Drawing.Point(185, 11);
this.button7.Name = "button7";
this.button7.Size = new System.Drawing.Size(93, 52);
this.button7.TabIndex = 1;
this.button7.Text = "Save";
this.button7.UseVisualStyleBackColor = true;
this.button7.Click += new System.EventHandler(this.button7_Click);
//
// button8
//
this.button8.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.button8.Location = new System.Drawing.Point(185, 69);
this.button8.Name = "button8";
this.button8.Size = new System.Drawing.Size(93, 52);
this.button8.TabIndex = 2;
this.button8.Text = "Reset";
this.button8.UseVisualStyleBackColor = true;
this.button8.Click += new System.EventHandler(this.button8_Click);
//
// openFileDialog1
//
this.openFileDialog1.Filter = "Images|*.png;*.jpg;*.bmp;*.gif";
//
// button9
//
this.button9.Location = new System.Drawing.Point(13, 40);
this.button9.Name = "button9";
this.button9.Size = new System.Drawing.Size(128, 23);
this.button9.TabIndex = 3;
this.button9.Text = "Set background picture";
this.button9.UseVisualStyleBackColor = true;
this.button9.Click += new System.EventHandler(this.button9_Click);
//
// button10
//
this.button10.Location = new System.Drawing.Point(13, 97);
this.button10.Name = "button10";
this.button10.Size = new System.Drawing.Size(128, 23);
this.button10.TabIndex = 4;
this.button10.Text = "Set font style";
this.button10.UseVisualStyleBackColor = true;
this.button10.Click += new System.EventHandler(this.button10_Click);
//
// fontDialog1
//
this.fontDialog1.Color = System.Drawing.Color.White;
this.fontDialog1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
//
// button3
//
this.button3.Location = new System.Drawing.Point(13, 69);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(128, 23);
this.button3.TabIndex = 5;
this.button3.Text = "Set font color";
this.button3.UseVisualStyleBackColor = true;
this.button3.Click += new System.EventHandler(this.button3_Click);
//
// button11
//
this.button11.Location = new System.Drawing.Point(13, 153);
this.button11.Name = "button11";
this.button11.Size = new System.Drawing.Size(128, 23);
this.button11.TabIndex = 6;
this.button11.Text = "Set sub-button color";
this.button11.UseVisualStyleBackColor = true;
this.button11.Click += new System.EventHandler(this.button11_Click);
//
// button12
//
this.button12.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.button12.Location = new System.Drawing.Point(185, 127);
this.button12.Name = "button12";
this.button12.Size = new System.Drawing.Size(93, 52);
this.button12.TabIndex = 7;
this.button12.Text = "Export Theme";
this.button12.UseVisualStyleBackColor = true;
this.button12.Click += new System.EventHandler(this.button12_Click);
//
// button13
//
this.button13.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.button13.Location = new System.Drawing.Point(185, 185);
this.button13.Name = "button13";
this.button13.Size = new System.Drawing.Size(93, 52);
this.button13.TabIndex = 8;
this.button13.Text = "Import theme";
this.button13.UseVisualStyleBackColor = true;
this.button13.Click += new System.EventHandler(this.button13_Click);
//
// openThemeDialog
//
this.openThemeDialog.Filter = "Text Files|*.txt";
//
// button2
//
this.button2.Location = new System.Drawing.Point(13, 210);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(128, 23);
this.button2.TabIndex = 9;
this.button2.Text = "Set textbox color";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// themeForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
this.ClientSize = new System.Drawing.Size(290, 248);
this.Controls.Add(this.button2);
this.Controls.Add(this.button13);
this.Controls.Add(this.button12);
this.Controls.Add(this.button11);
this.Controls.Add(this.button3);
this.Controls.Add(this.button10);
this.Controls.Add(this.button9);
this.Controls.Add(this.button8);
this.Controls.Add(this.button7);
this.Controls.Add(this.button5);
this.Controls.Add(this.button4);
this.Controls.Add(this.button1);
this.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.Name = "themeForm";
this.Text = "Create Your Theme";
this.Load += new System.EventHandler(this.themeForm_Load);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ColorDialog colorDialog1;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.Button button5;
private System.Windows.Forms.Button button7;
private System.Windows.Forms.Button button8;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.Button button9;
private System.Windows.Forms.Button button10;
private System.Windows.Forms.FontDialog fontDialog1;
private System.Windows.Forms.Button button3;
private System.Windows.Forms.Button button11;
private System.Windows.Forms.Button button12;
private System.Windows.Forms.Button button13;
private System.Windows.Forms.OpenFileDialog openThemeDialog;
private System.Windows.Forms.Button button2;
}
}

182
ThemeForm.cs Normal file
View File

@@ -0,0 +1,182 @@
using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System.Collections.Specialized;
namespace AndroidSideloader
{
public partial class themeForm : Form
{
public themeForm()
{
InitializeComponent();
}
private void button4_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
Properties.Settings.Default.ButtonColor = colorDialog1.Color;
}
private void button1_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
Properties.Settings.Default.BackColor = colorDialog1.Color;
}
private void button7_Click(object sender, EventArgs e)
{
Properties.Settings.Default.Save();
this.Close();
}
private void button8_Click(object sender, EventArgs e)
{
Properties.Settings.Default.BackColor = Color.FromArgb(45,45,45);
Properties.Settings.Default.ComboBoxColor = Color.FromArgb(45, 45, 45);
Properties.Settings.Default.TextBoxColor = Color.FromArgb(45,45,45);
Properties.Settings.Default.ButtonColor = SystemColors.ActiveCaptionText;
Properties.Settings.Default.SubButtonColor=Color.FromArgb(64, 64, 64);
Properties.Settings.Default.BackPicturePath = "";
Properties.Settings.Default.FontStyle = new Font("Microsoft Sans Serif", 11, FontStyle.Regular);
Properties.Settings.Default.FontColor = Color.White;
Properties.Settings.Default.Save();
}
private void button5_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
Properties.Settings.Default.ComboBoxColor = colorDialog1.Color;
}
private void button9_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
String extension = Path.GetExtension(openFileDialog1.FileName);
if (File.Exists(Environment.CurrentDirectory + "\\pic" + extension))
File.Delete(Environment.CurrentDirectory + "\\pic" + extension);
File.Copy(openFileDialog1.FileName, Environment.CurrentDirectory + "\\pic" + extension);
Properties.Settings.Default.BackPicturePath = Environment.CurrentDirectory + "\\pic" + extension ;
}
}
private void button10_Click(object sender, EventArgs e)
{
if (fontDialog1.ShowDialog() == DialogResult.OK)
{
Properties.Settings.Default.FontStyle = fontDialog1.Font;
}
}
private void button3_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
Properties.Settings.Default.FontColor = colorDialog1.Color;
}
private void button11_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
Properties.Settings.Default.SubButtonColor = colorDialog1.Color;
}
private void themeForm_Load(object sender, EventArgs e)
{
}
private void button12_Click(object sender, EventArgs e)
{
String BackColor = ColorTranslator.ToHtml(Properties.Settings.Default.BackColor);
String TextBoxColor = ColorTranslator.ToHtml(Properties.Settings.Default.TextBoxColor);
String ComboBoxColor = ColorTranslator.ToHtml(Properties.Settings.Default.ComboBoxColor);
String ButtonColor = ColorTranslator.ToHtml(Properties.Settings.Default.ButtonColor);
String SubButtonColor = ColorTranslator.ToHtml(Properties.Settings.Default.SubButtonColor);
String FontColor = ColorTranslator.ToHtml(Properties.Settings.Default.FontColor);
var cvt = new FontConverter();
string FontStyle = cvt.ConvertToString(Properties.Settings.Default.FontStyle);
int i;
if (File.Exists(Environment.CurrentDirectory + "\\theme.txt"))
{
if (File.Exists(Environment.CurrentDirectory + "\\theme11.txt"))
MessageBox.Show("You can't export more than 12 themes, sorry :(");
else
{
for (i = 1; i <= 10; i++)
{
if (File.Exists(Environment.CurrentDirectory + "\\theme" + i + ".txt"))
continue;
else
{
break;
}
}
File.WriteAllText(Environment.CurrentDirectory + "\\theme" + i + ".txt", "#SideloaderTheme# \n" + BackColor + "\n" + ButtonColor + "\n" + SubButtonColor + "\n"
+ TextBoxColor + "\n" + ComboBoxColor + "\n" + FontColor + "\n" + FontStyle);
MessageBox.Show("Theme exported as theme" + i + ".txt");
}
}
else
{
File.WriteAllText(Environment.CurrentDirectory + "\\theme.txt", "#SideloaderTheme# \n" + BackColor + "\n" + ButtonColor + "\n" + SubButtonColor + "\n"
+ TextBoxColor + "\n" + ComboBoxColor + "\n" + FontColor + "\n" + FontStyle);
MessageBox.Show("Theme exported as theme.txt");
}
}
private void button13_Click(object sender, EventArgs e)
{
openThemeDialog.InitialDirectory = Environment.CurrentDirectory;
if (openThemeDialog.ShowDialog() == DialogResult.OK) {
using (StreamReader sr = new StreamReader(openThemeDialog.FileName))
{
StringCollection myCol = new StringCollection();
myCol.AddRange(File.ReadAllLines(openThemeDialog.FileName));
if (myCol.Contains("#SideloaderTheme# "))
{
String[] settings = new String[myCol.Count];
myCol.CopyTo(settings, 0);
Color BackColor = ColorTranslator.FromHtml(settings[1]);
Color ButtonColor = ColorTranslator.FromHtml(settings[2]);
Color SubButtonColor = ColorTranslator.FromHtml(settings[3]);
Color TextBoxColor = ColorTranslator.FromHtml(settings[4]);
Color ComboBoxColor = ColorTranslator.FromHtml(settings[5]);
Color FontColor = ColorTranslator.FromHtml(settings[6]);
Properties.Settings.Default.BackColor = BackColor;
Properties.Settings.Default.ButtonColor = ButtonColor;
Properties.Settings.Default.SubButtonColor = SubButtonColor;
Properties.Settings.Default.TextBoxColor = TextBoxColor;
Properties.Settings.Default.ComboBoxColor = ComboBoxColor;
Properties.Settings.Default.FontColor = FontColor;
System.ComponentModel.TypeConverter converter =
System.ComponentModel.TypeDescriptor.GetConverter(typeof(Font));
var cvt = new FontConverter();
Font f = cvt.ConvertFromString(settings[7]) as Font;
Properties.Settings.Default.FontStyle = f;
}
else
MessageBox.Show("The file you've selected is not a Rookie's Sideloader theme file!");
}
}
}
private void button2_Click(object sender, EventArgs e)
{
if (colorDialog1.ShowDialog() == DialogResult.OK)
Properties.Settings.Default.TextBoxColor = colorDialog1.Color;
}
}
}

View File

@@ -1,123 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="DonationTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="colorDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="openFileDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>138, 17</value>
</metadata>
<metadata name="fontDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>278, 17</value>
</metadata>
<metadata name="openThemeDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>394, 17</value>
</metadata>
</root>

View File

@@ -1,264 +0,0 @@
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AndroidSideloader
{
/// <summary>
/// An iOS-style toggle switch control with smooth animation.
/// </summary>
public class ToggleSwitch : Control
{
private bool _checked;
private bool _isHovered;
private float _animationProgress; // 0 = off, 1 = on
private Timer _animationTimer;
private const int AnimationDuration = 80; // ms
private const int AnimationInterval = 8; // ~120fps
private float _animationStep;
// Colors
private Color _onColor = Color.FromArgb(93, 203, 173);
private Color _offColor = Color.FromArgb(60, 65, 75);
private Color _thumbColor = Color.White;
private Color _onHoverColor = Color.FromArgb(110, 215, 190);
private Color _offHoverColor = Color.FromArgb(75, 80, 90);
public event EventHandler CheckedChanged;
public ToggleSwitch()
{
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.UserPaint |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.StandardClick |
ControlStyles.StandardDoubleClick, true);
// Disable double-click so rapid clicks are treated as separate clicks
SetStyle(ControlStyles.StandardDoubleClick, false);
Size = new Size(44, 24);
Cursor = Cursors.Hand;
BackColor = Color.Transparent;
_animationTimer = new Timer { Interval = AnimationInterval };
_animationTimer.Tick += AnimationTimer_Tick;
_animationStep = (float)AnimationInterval / AnimationDuration;
}
[Category("Appearance")]
[Description("Gets or sets whether the toggle is in the 'on' state.")]
[DefaultValue(false)]
public bool Checked
{
get => _checked;
set
{
if (_checked != value)
{
_checked = value;
StartAnimation();
OnCheckedChanged(EventArgs.Empty);
}
}
}
/// <summary>
/// Sets the checked state without triggering animation or events.
/// Using this for initial state setup.
/// </summary>
public void SetCheckedSilent(bool value)
{
_checked = value;
_animationProgress = value ? 1f : 0f;
_animationTimer.Stop();
Invalidate();
}
[Category("Appearance")]
[Description("The color of the toggle when it is on.")]
public Color OnColor
{
get => _onColor;
set { _onColor = value; Invalidate(); }
}
[Category("Appearance")]
[Description("The color of the toggle when it is off.")]
public Color OffColor
{
get => _offColor;
set { _offColor = value; Invalidate(); }
}
[Category("Appearance")]
[Description("The color of the thumb (circle).")]
public Color ThumbColor
{
get => _thumbColor;
set { _thumbColor = value; Invalidate(); }
}
protected virtual void OnCheckedChanged(EventArgs e)
{
CheckedChanged?.Invoke(this, e);
}
private void StartAnimation()
{
if (!_animationTimer.Enabled)
{
_animationTimer.Start();
}
}
private void AnimationTimer_Tick(object sender, EventArgs e)
{
float target = _checked ? 1f : 0f;
if (_animationProgress < target)
{
_animationProgress += _animationStep;
if (_animationProgress >= target)
{
_animationProgress = target;
_animationTimer.Stop();
}
}
else if (_animationProgress > target)
{
_animationProgress -= _animationStep;
if (_animationProgress <= target)
{
_animationProgress = target;
_animationTimer.Stop();
}
}
else
{
_animationTimer.Stop();
}
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
int width = Width;
int height = Height;
int padding = 2;
int thumbDiameter = height - (padding * 2);
int trackRadius = height / 2;
Color trackColor;
if (_isHovered)
{
trackColor = InterpolateColor(_offHoverColor, _onHoverColor, _animationProgress);
}
else
{
trackColor = InterpolateColor(_offColor, _onColor, _animationProgress);
}
Rectangle trackRect = new Rectangle(0, 0, width, height);
using (GraphicsPath trackPath = CreateRoundedRectPath(trackRect, trackRadius))
using (SolidBrush trackBrush = new SolidBrush(trackColor))
{
g.FillPath(trackBrush, trackPath);
}
int thumbMinX = padding;
int thumbMaxX = width - thumbDiameter - padding;
float easedProgress = EaseOutQuad(_animationProgress);
int thumbX = (int)(thumbMinX + (thumbMaxX - thumbMinX) * easedProgress);
int thumbY = padding;
Rectangle shadowRect = new Rectangle(thumbX + 1, thumbY + 1, thumbDiameter, thumbDiameter);
using (SolidBrush shadowBrush = new SolidBrush(Color.FromArgb(40, 0, 0, 0)))
{
g.FillEllipse(shadowBrush, shadowRect);
}
Rectangle thumbRect = new Rectangle(thumbX, thumbY, thumbDiameter, thumbDiameter);
using (SolidBrush thumbBrush = new SolidBrush(_thumbColor))
{
g.FillEllipse(thumbBrush, thumbRect);
}
}
private float EaseOutQuad(float t)
{
return t * (2 - t);
}
private Color InterpolateColor(Color from, Color to, float progress)
{
int r = (int)(from.R + (to.R - from.R) * progress);
int g = (int)(from.G + (to.G - from.G) * progress);
int b = (int)(from.B + (to.B - from.B) * progress);
int a = (int)(from.A + (to.A - from.A) * progress);
return Color.FromArgb(a, r, g, b);
}
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
{
GraphicsPath path = new GraphicsPath();
int diameter = radius * 2;
path.AddArc(rect.X, rect.Y, diameter, diameter, 180, 90);
path.AddArc(rect.Right - diameter, rect.Y, diameter, diameter, 270, 90);
path.AddArc(rect.Right - diameter, rect.Bottom - diameter, diameter, diameter, 0, 90);
path.AddArc(rect.X, rect.Bottom - diameter, diameter, diameter, 90, 90);
path.CloseFigure();
return path;
}
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
_isHovered = true;
Invalidate();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
_isHovered = false;
Invalidate();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
// Toggle immediately on mouse down for responsive feel
_checked = !_checked;
StartAnimation();
OnCheckedChanged(EventArgs.Empty);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_animationTimer?.Stop();
_animationTimer?.Dispose();
}
base.Dispose(disposing);
}
}
}

View File

@@ -1,44 +0,0 @@
using System.Drawing;
using System.Windows.Forms;
namespace AndroidSideloader
{
public class Transparenter
{
public static void MakeTransparent(Control control, Graphics g)
{
Control parent = control.Parent;
if (parent == null)
{
return;
}
Rectangle bounds = control.Bounds;
Control.ControlCollection siblings = parent.Controls;
int index = siblings.IndexOf(control);
Bitmap behind = null;
for (int i = siblings.Count - 1; i > index; i--)
{
Control c = siblings[i];
if (!c.Bounds.IntersectsWith(bounds))
{
continue;
}
if (behind == null)
{
behind = new Bitmap(control.Parent.ClientSize.Width, control.Parent.ClientSize.Height);
}
c.DrawToBitmap(behind, c.Bounds);
}
if (behind == null)
{
return;
}
g.DrawImage(behind, control.ClientRectangle, bounds, GraphicsUnit.Pixel);
behind.Dispose();
}
}
}

190
UpdateForm.Designer.cs generated
View File

@@ -1,190 +0,0 @@
namespace AndroidSideloader
{
partial class UpdateForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.YesUpdate = new AndroidSideloader.RoundButton();
this.panel3 = new System.Windows.Forms.Panel();
this.UpdateTextBox = new System.Windows.Forms.RichTextBox();
this.UpdateVerLabel = new System.Windows.Forms.Label();
this.CurVerLabel = new System.Windows.Forms.Label();
this.SkipUpdate = new System.Windows.Forms.Label();
this.panel1.SuspendLayout();
this.panel3.SuspendLayout();
this.SuspendLayout();
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.panel1.Controls.Add(this.YesUpdate);
this.panel1.Controls.Add(this.panel3);
this.panel1.Controls.Add(this.UpdateVerLabel);
this.panel1.Controls.Add(this.CurVerLabel);
this.panel1.Controls.Add(this.SkipUpdate);
this.panel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Padding = new System.Windows.Forms.Padding(20, 50, 20, 20);
this.panel1.Size = new System.Drawing.Size(480, 320);
this.panel1.TabIndex = 5;
this.panel1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseDown);
this.panel1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseMove);
this.panel1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseUp);
//
// YesUpdate
//
this.YesUpdate.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(113)))), ((int)(((byte)(223)))), ((int)(((byte)(193)))));
this.YesUpdate.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.YesUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.YesUpdate.BackColor = System.Drawing.Color.Transparent;
this.YesUpdate.DialogResult = System.Windows.Forms.DialogResult.OK;
this.YesUpdate.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.YesUpdate.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.YesUpdate.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.YesUpdate.Font = new System.Drawing.Font("Segoe UI", 10F, System.Drawing.FontStyle.Bold);
this.YesUpdate.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(20)))), ((int)(((byte)(20)))));
this.YesUpdate.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.YesUpdate.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(73)))), ((int)(((byte)(183)))), ((int)(((byte)(153)))));
this.YesUpdate.Location = new System.Drawing.Point(340, 259);
this.YesUpdate.Name = "YesUpdate";
this.YesUpdate.Radius = 6;
this.YesUpdate.Size = new System.Drawing.Size(120, 36);
this.YesUpdate.Stroke = false;
this.YesUpdate.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
this.YesUpdate.TabIndex = 2;
this.YesUpdate.Text = "Update Now";
this.YesUpdate.Transparency = false;
this.YesUpdate.Click += new System.EventHandler(this.YesUpdate_Click);
//
// panel3
//
this.panel3.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel3.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.panel3.Controls.Add(this.UpdateTextBox);
this.panel3.Location = new System.Drawing.Point(20, 50);
this.panel3.Name = "panel3";
this.panel3.Padding = new System.Windows.Forms.Padding(12, 10, 12, 10);
this.panel3.Size = new System.Drawing.Size(440, 200);
this.panel3.TabIndex = 0;
//
// UpdateTextBox
//
this.UpdateTextBox.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.UpdateTextBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.UpdateTextBox.Dock = System.Windows.Forms.DockStyle.Fill;
this.UpdateTextBox.Font = new System.Drawing.Font("Segoe UI", 9.5F);
this.UpdateTextBox.ForeColor = System.Drawing.Color.White;
this.UpdateTextBox.Location = new System.Drawing.Point(12, 10);
this.UpdateTextBox.Margin = new System.Windows.Forms.Padding(6);
this.UpdateTextBox.Name = "UpdateTextBox";
this.UpdateTextBox.ReadOnly = true;
this.UpdateTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
this.UpdateTextBox.Size = new System.Drawing.Size(416, 180);
this.UpdateTextBox.TabIndex = 1;
this.UpdateTextBox.Text = "";
this.UpdateTextBox.TextChanged += new System.EventHandler(this.UpdateTextBox_TextChanged);
this.UpdateTextBox.MouseDown += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseDown);
this.UpdateTextBox.MouseMove += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseMove);
this.UpdateTextBox.MouseUp += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseUp);
//
// UpdateVerLabel
//
this.UpdateVerLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.UpdateVerLabel.AutoSize = true;
this.UpdateVerLabel.BackColor = System.Drawing.Color.Transparent;
this.UpdateVerLabel.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.UpdateVerLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.UpdateVerLabel.Location = new System.Drawing.Point(20, 285);
this.UpdateVerLabel.Name = "UpdateVerLabel";
this.UpdateVerLabel.Size = new System.Drawing.Size(95, 15);
this.UpdateVerLabel.TabIndex = 3;
this.UpdateVerLabel.Text = "Update Version:";
//
// CurVerLabel
//
this.CurVerLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.CurVerLabel.AutoSize = true;
this.CurVerLabel.BackColor = System.Drawing.Color.Transparent;
this.CurVerLabel.Font = new System.Drawing.Font("Segoe UI", 9F);
this.CurVerLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.CurVerLabel.Location = new System.Drawing.Point(20, 266);
this.CurVerLabel.Name = "CurVerLabel";
this.CurVerLabel.Size = new System.Drawing.Size(91, 15);
this.CurVerLabel.TabIndex = 2;
this.CurVerLabel.Text = "Current Version:";
//
// SkipUpdate
//
this.SkipUpdate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.SkipUpdate.AutoSize = true;
this.SkipUpdate.BackColor = System.Drawing.Color.Transparent;
this.SkipUpdate.Cursor = System.Windows.Forms.Cursors.Hand;
this.SkipUpdate.Font = new System.Drawing.Font("Segoe UI", 8.5F);
this.SkipUpdate.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(160)))), ((int)(((byte)(165)))), ((int)(((byte)(175)))));
this.SkipUpdate.Location = new System.Drawing.Point(380, 297);
this.SkipUpdate.Name = "SkipUpdate";
this.SkipUpdate.Size = new System.Drawing.Size(73, 15);
this.SkipUpdate.TabIndex = 4;
this.SkipUpdate.Text = "Skip for now";
this.SkipUpdate.Click += new System.EventHandler(this.SkipUpdate_Click);
//
// UpdateForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
this.ClientSize = new System.Drawing.Size(480, 320);
this.ControlBox = false;
this.Controls.Add(this.panel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "UpdateForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseDown);
this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseMove);
this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.UpdateForm_MouseUp);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel3.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Label SkipUpdate;
private System.Windows.Forms.Label CurVerLabel;
private System.Windows.Forms.Label UpdateVerLabel;
private System.Windows.Forms.Panel panel3;
private System.Windows.Forms.RichTextBox UpdateTextBox;
private System.Windows.Forms.Panel panel1;
private RoundButton YesUpdate;
}
}

View File

@@ -1,250 +0,0 @@
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace AndroidSideloader
{
public partial class UpdateForm : Form
{
private bool mouseDown;
private Point lastLocation;
// Modern theme colors
private static readonly Color BackgroundColor = Color.FromArgb(20, 24, 29);
private static readonly Color PanelColor = Color.FromArgb(28, 32, 38);
private static readonly Color TextColor = Color.White;
private static readonly Color SecondaryTextColor = Color.FromArgb(160, 165, 175);
private static readonly Color BorderColor = Color.FromArgb(60, 65, 75);
public UpdateForm()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = Icon.ExtractAssociatedIcon(Application.ExecutablePath);
ApplyModernTheme();
CenterToScreen();
CurVerLabel.Text = $"Current Version: {Updater.LocalVersion}";
UpdateVerLabel.Text = $"Update Version: {Updater.currentVersion}";
UpdateTextBox.Text = Updater.changelog;
}
private void ApplyModernTheme()
{
// Form settings
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = BackgroundColor;
this.DoubleBuffered = true;
// Enable double buffering on panels for smooth rounded corners
EnableDoubleBuffering(panel1);
EnableDoubleBuffering(panel3);
// Add custom paint handler for rounded panel1 (main container)
panel1.Paint += Panel1_Paint;
panel1.BackColor = Color.Transparent;
// Add custom paint handler for rounded panel3 (changelog container)
panel3.Paint += Panel3_Paint;
panel3.BackColor = Color.Transparent;
// Update textbox to have matching background
UpdateTextBox.BackColor = PanelColor;
// Add title label
var titleLabel = new Label
{
Text = "Update Available",
Font = new Font("Segoe UI", 12F, FontStyle.Bold),
ForeColor = TextColor,
BackColor = Color.Transparent,
AutoSize = true,
Location = new Point(20, 15)
};
panel1.Controls.Add(titleLabel);
titleLabel.BringToFront();
// Add close button
var closeButton = new Label
{
Text = "✕",
Font = new Font("Segoe UI", 10F),
ForeColor = SecondaryTextColor,
BackColor = Color.Transparent,
AutoSize = true,
Cursor = Cursors.Hand,
Location = new Point(this.ClientSize.Width - 30, 10),
Anchor = AnchorStyles.Top | AnchorStyles.Right
};
closeButton.Click += (s, e) => Close();
closeButton.MouseEnter += (s, e) => closeButton.ForeColor = Color.FromArgb(220, 80, 80);
closeButton.MouseLeave += (s, e) => closeButton.ForeColor = SecondaryTextColor;
panel1.Controls.Add(closeButton);
closeButton.BringToFront();
// Apply custom painting for form rounded corners and border
this.Paint += UpdateForm_Paint;
}
private void EnableDoubleBuffering(Panel panel)
{
typeof(Panel).InvokeMember("DoubleBuffered",
System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic,
null, panel, new object[] { true });
}
private void Panel1_Paint(object sender, PaintEventArgs e)
{
var panel = sender as Panel;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int radius = 12;
var rect = new Rectangle(0, 0, panel.Width - 1, panel.Height - 1);
using (var path = CreateRoundedRectPath(rect, radius))
{
// Fill background
using (var brush = new SolidBrush(BackgroundColor))
{
e.Graphics.FillPath(brush, path);
}
// Draw border
using (var pen = new Pen(BorderColor, 1f))
{
e.Graphics.DrawPath(pen, path);
}
}
// Apply rounded region to clip children
using (var regionPath = CreateRoundedRectPath(new Rectangle(0, 0, panel.Width, panel.Height), radius))
{
panel.Region = new Region(regionPath);
}
}
private void Panel3_Paint(object sender, PaintEventArgs e)
{
var panel = sender as Panel;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int radius = 10;
var rect = new Rectangle(0, 0, panel.Width - 1, panel.Height - 1);
using (var path = CreateRoundedRectPath(rect, radius))
{
// Fill background
using (var brush = new SolidBrush(PanelColor))
{
e.Graphics.FillPath(brush, path);
}
// Draw border
using (var pen = new Pen(BorderColor, 1f))
{
e.Graphics.DrawPath(pen, path);
}
}
// Apply rounded region to clip children
using (var regionPath = CreateRoundedRectPath(new Rectangle(0, 0, panel.Width, panel.Height), radius))
{
panel.Region = new Region(regionPath);
}
}
private void UpdateForm_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
int w = this.ClientSize.Width;
int h = this.ClientSize.Height;
int radius = 12;
// Draw border
using (var borderPen = new Pen(BorderColor, 1f))
using (var path = CreateRoundedRectPath(new Rectangle(0, 0, w - 1, h - 1), radius))
{
e.Graphics.DrawPath(borderPen, path);
}
// Apply rounded region
using (var regionPath = CreateRoundedRectPath(new Rectangle(0, 0, w, h), radius))
{
this.Region = new Region(regionPath);
}
}
private GraphicsPath CreateRoundedRectPath(Rectangle rect, int radius)
{
GraphicsPath path = new GraphicsPath();
if (radius <= 0)
{
path.AddRectangle(rect);
return path;
}
int diameter = radius * 2;
diameter = Math.Min(diameter, Math.Min(rect.Width, rect.Height));
radius = diameter / 2;
Rectangle arcRect = new Rectangle(rect.Location, new Size(diameter, diameter));
// Top left arc
path.AddArc(arcRect, 180, 90);
// Top right arc
arcRect.X = rect.Right - diameter;
path.AddArc(arcRect, 270, 90);
// Bottom right arc
arcRect.Y = rect.Bottom - diameter;
path.AddArc(arcRect, 0, 90);
// Bottom left arc
arcRect.X = rect.Left;
path.AddArc(arcRect, 90, 90);
path.CloseFigure();
return path;
}
private void YesUpdate_Click(object sender, EventArgs e)
{
Updater.doUpdate();
Close();
}
private void SkipUpdate_Click(object sender, EventArgs e)
{
Close();
}
private void UpdateTextBox_TextChanged(object sender, EventArgs e)
{
}
private void UpdateForm_MouseDown(object sender, MouseEventArgs e)
{
mouseDown = true;
lastLocation = e.Location;
}
private void UpdateForm_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown)
{
Location = new Point(
Location.X - lastLocation.X + e.X, Location.Y - lastLocation.Y + e.Y);
Update();
}
}
private void UpdateForm_MouseUp(object sender, MouseEventArgs e)
{
mouseDown = false;
}
}
}

View File

@@ -1,110 +1,69 @@
using System;
using System.Text;
using System.Diagnostics;
using JR.Utils.GUI.Forms;
using System.Net;
using System.Windows.Forms;
using System.Net.Http;
using System.Threading.Tasks;
using System.IO;
using AndroidSideloader;
namespace AndroidSideloader
{
internal class Updater
class Updater
{
public static string AppName { get; set; }
public static string Repository { get; set; }
private static readonly string RawGitHubUrl = "https://raw.githubusercontent.com/VRPirates/rookie";
public static readonly string GitHubUrl = "https://github.com/VRPirates/rookie";
public static string Repostory { get; set; }
private static string RawGitHubUrl;
private static string GitHubUrl;
public static readonly string LocalVersion = "3.0.1";
static readonly public string LocalVersion = "2.0-WIP";
public static string currentVersion = string.Empty;
public static string changelog = string.Empty;
// Check if there is a new version of the sideloader
private static async Task<bool> IsUpdateAvailableAsync()
{
using (HttpClient client = new HttpClient())
{
try
{
currentVersion = await client.GetStringAsync($"{RawGitHubUrl}/master/version");
changelog = await client.GetStringAsync($"{RawGitHubUrl}/master/changelog.txt");
currentVersion = currentVersion.Trim();
}
catch (HttpRequestException)
{
return false;
}
}
// Compare versions - only return true if server version is greater than local version
return CompareVersions(currentVersion, LocalVersion.Trim()) > 0;
}
// Compares two semantic version strings (e.g., "2.35")
// returns: 1 if version1 > version2, -1 if version1 < version2, 0 if equal
private static int CompareVersions(string version1, string version2)
private static bool IsUpdateAvailable()
{
HttpClient client = new HttpClient();
try
{
// Parse versions into parts
string[] parts1 = version1.Split('.');
string[] parts2 = version2.Split('.');
// Compare each part
int maxLength = Math.Max(parts1.Length, parts2.Length);
for (int i = 0; i < maxLength; i++)
{
int v1 = i < parts1.Length && int.TryParse(parts1[i], out int p1) ? p1 : 0;
int v2 = i < parts2.Length && int.TryParse(parts2[i], out int p2) ? p2 : 0;
if (v1 > v2) return 1;
if (v1 < v2) return -1;
}
return 0; // Versions are equal
}
catch
{
// Fallback to string comparison if parsing fails
return string.Compare(version1, version2, StringComparison.Ordinal);
currentVersion = client.GetStringAsync($"{RawGitHubUrl}/master/version").Result;
if (currentVersion.Length > LocalVersion.Length)
currentVersion = currentVersion.Remove(currentVersion.Length - 1);
changelog = client.GetStringAsync($"{RawGitHubUrl}/master/changelog.txt").Result;
client.Dispose();
}
catch { return false; }
return LocalVersion != currentVersion;
}
// Ask the user if they want to update
public static async Task Update()
public static void Update()
{
if (await IsUpdateAvailableAsync())
{
UpdateForm upForm = new UpdateForm();
_ = upForm.ShowDialog();
}
RawGitHubUrl = $"https://raw.githubusercontent.com/{Repostory}";
GitHubUrl = $"https://github.com/{Repostory}";
if (IsUpdateAvailable())
doUpdate();
}
// If the user wants to update
public static void doUpdate()
private static void doUpdate()
{
DialogResult dialogResult = FlexibleMessageBox.Show($"There is a new update you have version {LocalVersion}, do you want to update?\nCHANGELOG\n{changelog}", $"Version {currentVersion} is available", MessageBoxButtons.YesNo);
if (dialogResult != DialogResult.Yes)
return;
try
{
ADB.RunAdbCommandToString("kill-server");
using (WebClient fileClient = new WebClient())
using (var fileClient = new WebClient())
{
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Logger.Log($"Downloading update from {GitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe to {AppName} v{currentVersion}.exe");
Logger.Log($"Downloading update from {RawGitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe to {AppName} v{currentVersion}.exe");
fileClient.DownloadFile($"{GitHubUrl}/releases/download/v{currentVersion}/{AppName}.exe", $"{AppName} v{currentVersion}.exe");
Logger.Log($"Starting {AppName} v{currentVersion}.exe");
Process.Start($"{AppName} v{currentVersion}.exe");
fileClient.Dispose();
}
// Delete current version
Logger.Log($"Starting {AppName} v{currentVersion}.exe");
Process.Start($"{AppName} v{currentVersion}.exe");
AndroidSideloader.Utilities.GeneralUtilities.Melt();
}
catch (Exception ex)
{
// Handle specific exceptions that might occur during the update process
Logger.Log($"Update failed: {ex.Message}");
}
catch { }
}
}
}
}

186
UsernameForm.Designer.cs generated
View File

@@ -1,94 +1,92 @@
namespace AndroidSideloader
{
partial class UsernameForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new AndroidSideloader.RoundButton();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
this.textBox1.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.textBox1.ForeColor = System.Drawing.Color.White;
this.textBox1.Location = new System.Drawing.Point(13, 13);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(418, 23);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "Enter your username here";
//
// button1
//
this.button1.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
this.button1.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
this.button1.BackColor = System.Drawing.Color.Transparent;
this.button1.DialogResult = System.Windows.Forms.DialogResult.OK;
this.button1.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.button1.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(28)))), ((int)(((byte)(35)))));
this.button1.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.button1.Font = new System.Drawing.Font("Microsoft Sans Serif", 11.25F);
this.button1.ForeColor = System.Drawing.Color.White;
this.button1.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
this.button1.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(25)))), ((int)(((byte)(25)))), ((int)(((byte)(25)))));
this.button1.Location = new System.Drawing.Point(13, 51);
this.button1.Name = "button1";
this.button1.Radius = 5;
this.button1.Size = new System.Drawing.Size(418, 34);
this.button1.Stroke = true;
this.button1.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(74)))), ((int)(((byte)(74)))), ((int)(((byte)(74)))));
this.button1.TabIndex = 2;
this.button1.Text = "Create User.Json";
this.button1.Transparency = false;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// UsernameForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
this.ClientSize = new System.Drawing.Size(443, 100);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.ForeColor = System.Drawing.Color.White;
this.MaximumSize = new System.Drawing.Size(459, 139);
this.MinimumSize = new System.Drawing.Size(459, 139);
this.Name = "UsernameForm";
this.Text = "USER.JSON";
this.Load += new System.EventHandler(this.usernameForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
private RoundButton button1;
}
}
namespace AndroidSideloader
{
partial class UsernameForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.BackColor = global::AndroidSideloader.Properties.Settings.Default.TextBoxColor;
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "TextBoxColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.textBox1.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.textBox1.ForeColor = System.Drawing.Color.White;
this.textBox1.Location = new System.Drawing.Point(13, 13);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(418, 24);
this.textBox1.TabIndex = 0;
this.textBox1.Text = "Enter your username here";
//
// button1
//
this.button1.BackColor = global::AndroidSideloader.Properties.Settings.Default.SubButtonColor;
this.button1.DataBindings.Add(new System.Windows.Forms.Binding("Font", global::AndroidSideloader.Properties.Settings.Default, "FontStyle", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.button1.DataBindings.Add(new System.Windows.Forms.Binding("ForeColor", global::AndroidSideloader.Properties.Settings.Default, "FontColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.button1.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "SubButtonColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.button1.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.button1.Font = global::AndroidSideloader.Properties.Settings.Default.FontStyle;
this.button1.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.button1.Location = new System.Drawing.Point(13, 51);
this.button1.Margin = new System.Windows.Forms.Padding(0);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(418, 34);
this.button1.TabIndex = 1;
this.button1.Text = "Create User.Json";
this.button1.UseVisualStyleBackColor = false;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// UsernameForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = global::AndroidSideloader.Properties.Settings.Default.BackColor;
this.ClientSize = new System.Drawing.Size(443, 100);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox1);
this.DataBindings.Add(new System.Windows.Forms.Binding("BackColor", global::AndroidSideloader.Properties.Settings.Default, "BackColor", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
this.ForeColor = System.Drawing.Color.White;
this.MaximumSize = new System.Drawing.Size(459, 139);
this.MinimumSize = new System.Drawing.Size(459, 139);
this.Name = "UsernameForm";
this.ShowIcon = false;
this.Text = "USER.JSON";
this.Load += new System.EventHandler(this.usernameForm_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.Button button1;
}
}

View File

@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace AndroidSideloader
{
@@ -12,12 +12,9 @@ namespace AndroidSideloader
public UsernameForm()
{
InitializeComponent();
// Use same icon as the executable
this.Icon = System.Drawing.Icon.ExtractAssociatedIcon(Application.ExecutablePath);
}
private string defaultText;
string defaultText;
private void usernameForm_Load(object sender, EventArgs e)
{
@@ -29,24 +26,20 @@ namespace AndroidSideloader
{
if (textBox1.Text == defaultText || textBox1.Text.Length == 0)
{
_ = MessageBox.Show("Please enter your username first");
MessageBox.Show("Please enter your username first");
return;
}
Thread t1 = new Thread(() =>
{
createUserJson(textBox1.Text);
})
{
IsBackground = true
};
});
t1.IsBackground = true;
t1.Start();
while (t1.IsAlive)
{
await Task.Delay(100);
}
MainForm.notify("Done");
@@ -56,11 +49,11 @@ namespace AndroidSideloader
public static void createUserJson(string username)
{
_ = ADB.RunAdbCommandToString($"shell settings put global username \"{username}\"");
foreach (string jsonFileName in userJsons)
ADB.RunAdbCommandToString($"shell settings put global username {username}");
foreach (var jsonFileName in userJsons)
{
createUserJsonByName(username, jsonFileName);
_ = ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{jsonFileName}\" " + " /sdcard/");
ADB.RunAdbCommandToString("push \"" + Environment.CurrentDirectory + $"\\{jsonFileName}\" " + " /sdcard/");
File.Delete(jsonFileName);
}
@@ -85,6 +78,6 @@ namespace AndroidSideloader
}
}
}

View File

@@ -1,554 +0,0 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace AndroidSideloader.Utilities
{
// Provides DNS fallback functionality using Cloudflare DNS (1.1.1.1, 1.0.0.1) if system DNS fails to resolve critical hostnames
// Also provides a proxy for rclone that handles DNS resolution
public static class DnsHelper
{
private static readonly string[] FallbackDnsServers = { "1.1.1.1", "1.0.0.1" };
private static readonly string[] CriticalHostnames =
{
"raw.githubusercontent.com",
"downloads.rclone.org",
"vrpirates.wiki",
"github.com"
};
private static readonly ConcurrentDictionary<string, IPAddress> _dnsCache =
new ConcurrentDictionary<string, IPAddress>(StringComparer.OrdinalIgnoreCase);
private static readonly object _lock = new object();
// Local proxy for rclone
private static TcpListener _proxyListener;
private static CancellationTokenSource _proxyCts;
private static int _proxyPort;
private static bool _initialized;
private static bool _proxyRunning;
public static bool UseFallbackDns { get; private set; }
// Gets the proxy URL for rclone to use, or empty string if not needed
public static string ProxyUrl => _proxyRunning ? $"http://127.0.0.1:{_proxyPort}" : string.Empty;
// Called after vrp-public.json is created/updated to test the hostname
// Enable fallback DNS if the hostname fails on system DNS but works with fallback DNS
public static void TestPublicConfigDns()
{
string hostname = GetPublicConfigHostname();
if (string.IsNullOrEmpty(hostname))
return;
lock (_lock)
{
// If already using fallback, just pre-resolve the new hostname
if (UseFallbackDns)
{
var ip = ResolveWithFallbackDns(hostname);
if (ip != null)
{
_dnsCache[hostname] = ip;
Logger.Log($"Pre-resolved public config hostname {hostname} -> {ip}");
}
return;
}
// Test if system DNS can resolve the public config hostname
bool systemDnsWorks = TestHostnameWithSystemDns(hostname);
if (!systemDnsWorks)
{
Logger.Log($"System DNS failed for {hostname}. Testing fallback...", LogLevel.WARNING);
// Test if fallback DNS works for this hostname
var ip = ResolveWithFallbackDns(hostname);
if (ip != null)
{
UseFallbackDns = true;
_dnsCache[hostname] = ip;
Logger.Log($"Enabled fallback DNS for {hostname} -> {ip}", LogLevel.INFO);
ServicePointManager.DnsRefreshTimeout = 0;
// Pre-resolve base hostnames too
PreResolveHostnames(CriticalHostnames);
// Start proxy if not already running
if (!_proxyRunning)
{
StartProxy();
}
}
else
{
Logger.Log($"Both system and fallback DNS failed for {hostname}", LogLevel.ERROR);
}
}
else
{
Logger.Log($"System DNS works for public config hostname: {hostname}");
}
}
}
private static string GetPublicConfigHostname()
{
try
{
string configPath = Path.Combine(Environment.CurrentDirectory, "vrp-public.json");
if (!File.Exists(configPath))
return null;
var config = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(configPath));
if (config != null && config.TryGetValue("baseUri", out string baseUri))
{
return ExtractHostname(baseUri);
}
}
catch (Exception ex)
{
Logger.Log($"Failed to get hostname from vrp-public.json: {ex.Message}", LogLevel.WARNING);
}
return null;
}
private static string[] GetCriticalHostnames()
{
var hostnames = new List<string>(CriticalHostnames);
string host = GetPublicConfigHostname();
if (!string.IsNullOrWhiteSpace(host) && !hostnames.Contains(host))
{
hostnames.Add(host);
Logger.Log($"Added {host} from vrp-public.json to critical hostnames");
}
return hostnames.ToArray();
}
private static string ExtractHostname(string uriString)
{
if (string.IsNullOrWhiteSpace(uriString)) return null;
if (!uriString.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
!uriString.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
uriString = "https://" + uriString;
}
if (Uri.TryCreate(uriString, UriKind.Absolute, out Uri uri))
return uri.Host;
// Fallback: manual extraction
string hostname = uriString.Replace("https://", "").Replace("http://", "");
int idx = hostname.IndexOfAny(new[] { '/', ':' });
return idx > 0 ? hostname.Substring(0, idx) : hostname;
}
public static void Initialize()
{
lock (_lock)
{
if (_initialized) return;
Logger.Log("Testing DNS resolution for critical hostnames...");
var hostnames = GetCriticalHostnames();
if (TestDns(hostnames, useSystem: true))
{
Logger.Log("System DNS is working correctly.");
}
else
{
Logger.Log("System DNS failed. Testing Cloudflare DNS fallback...", LogLevel.WARNING);
if (TestDns(hostnames, useSystem: false))
{
UseFallbackDns = true;
Logger.Log("Using Cloudflare DNS fallback.", LogLevel.INFO);
PreResolveHostnames(hostnames);
ServicePointManager.DnsRefreshTimeout = 0;
StartProxy();
}
else
{
Logger.Log("Both system and fallback DNS failed.", LogLevel.ERROR);
}
}
_initialized = true;
}
}
public static void Cleanup() => StopProxy();
private static bool TestHostnameWithSystemDns(string hostname)
{
try
{
var addresses = Dns.GetHostAddresses(hostname);
return addresses?.Length > 0;
}
catch
{
return false;
}
}
private static bool TestDns(string[] hostnames, bool useSystem)
{
if (useSystem)
{
return hostnames.All(h =>
{
try { return Dns.GetHostAddresses(h)?.Length > 0; }
catch { return false; }
});
}
return FallbackDnsServers.Any(server =>
{
try { return ResolveWithDns(hostnames[0], server)?.Count > 0; }
catch { return false; }
});
}
private static void PreResolveHostnames(string[] hostnames)
{
foreach (string hostname in hostnames)
{
var ip = ResolveWithFallbackDns(hostname);
if (ip != null)
{
_dnsCache[hostname] = ip;
Logger.Log($"Pre-resolved {hostname} -> {ip}");
}
}
}
private static IPAddress ResolveWithFallbackDns(string hostname)
{
foreach (string server in FallbackDnsServers)
{
try
{
var addresses = ResolveWithDns(hostname, server);
if (addresses?.Count > 0) return addresses[0];
}
catch { }
}
return null;
}
private static List<IPAddress> ResolveWithDns(string hostname, string dnsServer, int timeoutMs = 5000)
{
using (var udp = new UdpClient { Client = { ReceiveTimeout = timeoutMs, SendTimeout = timeoutMs } })
{
byte[] query = BuildDnsQuery(hostname);
udp.Send(query, query.Length, new IPEndPoint(IPAddress.Parse(dnsServer), 53));
IPEndPoint remoteEp = null;
return ParseDnsResponse(udp.Receive(ref remoteEp));
}
}
private static byte[] BuildDnsQuery(string hostname)
{
using (var ms = new MemoryStream())
using (var writer = new BinaryWriter(ms))
{
writer.Write(IPAddress.HostToNetworkOrder((short)new Random().Next(0, ushort.MaxValue)));
writer.Write(IPAddress.HostToNetworkOrder((short)0x0100)); // Flags
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Questions
writer.Write(IPAddress.HostToNetworkOrder((short)0)); // Answer RRs
writer.Write(IPAddress.HostToNetworkOrder((short)0)); // Authority RRs
writer.Write(IPAddress.HostToNetworkOrder((short)0)); // Additional RRs
foreach (string label in hostname.Split('.'))
{
writer.Write((byte)label.Length);
writer.Write(Encoding.ASCII.GetBytes(label));
}
writer.Write((byte)0);
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Type A
writer.Write(IPAddress.HostToNetworkOrder((short)1)); // Class IN
return ms.ToArray();
}
}
private static List<IPAddress> ParseDnsResponse(byte[] response)
{
var addresses = new List<IPAddress>();
if (response.Length < 12) return addresses;
int pos = 12;
while (pos < response.Length && response[pos] != 0) pos += response[pos] + 1;
pos += 5;
int answerCount = (response[6] << 8) | response[7];
for (int i = 0; i < answerCount && pos + 12 <= response.Length; i++)
{
pos += (response[pos] & 0xC0) == 0xC0 ? 2 : SkipName(response, pos);
if (pos + 10 > response.Length) break;
ushort type = (ushort)((response[pos] << 8) | response[pos + 1]);
ushort rdLength = (ushort)((response[pos + 8] << 8) | response[pos + 9]);
pos += 10;
if (pos + rdLength > response.Length) break;
if (type == 1 && rdLength == 4)
addresses.Add(new IPAddress(new[] { response[pos], response[pos + 1], response[pos + 2], response[pos + 3] }));
pos += rdLength;
}
return addresses;
}
private static int SkipName(byte[] data, int pos)
{
int start = pos;
while (pos < data.Length && data[pos] != 0) pos += data[pos] + 1;
return pos - start + 1;
}
public static IPAddress ResolveHostname(string hostname, bool alwaysTryFallback = false)
{
if (_dnsCache.TryGetValue(hostname, out IPAddress cached))
return cached;
try
{
var addresses = Dns.GetHostAddresses(hostname);
if (addresses?.Length > 0)
{
_dnsCache[hostname] = addresses[0];
return addresses[0];
}
}
catch { }
if (alwaysTryFallback || UseFallbackDns || !_initialized)
{
var ip = ResolveWithFallbackDns(hostname);
if (ip != null)
{
_dnsCache[hostname] = ip;
return ip;
}
}
return null;
}
public static HttpWebRequest CreateWebRequest(string url)
{
var uri = new Uri(url);
if (!UseFallbackDns)
{
try
{
Dns.GetHostAddresses(uri.Host);
return (HttpWebRequest)WebRequest.Create(url);
}
catch
{
if (!_initialized) Initialize();
}
}
if (UseFallbackDns)
{
var ip = ResolveHostname(uri.Host, alwaysTryFallback: true);
if (ip != null)
{
var builder = new UriBuilder(uri) { Host = ip.ToString() };
var request = (HttpWebRequest)WebRequest.Create(builder.Uri);
request.Host = uri.Host;
return request;
}
}
return (HttpWebRequest)WebRequest.Create(url);
}
private static void StartProxy()
{
try
{
// Find an available port
_proxyListener = new TcpListener(IPAddress.Loopback, 0);
_proxyListener.Start();
_proxyPort = ((IPEndPoint)_proxyListener.LocalEndpoint).Port;
_proxyCts = new CancellationTokenSource();
_proxyRunning = true;
Logger.Log($"Started DNS proxy on port {_proxyPort}");
// Accept connections in background
Task.Run(() => ProxyAcceptLoop(_proxyCts.Token));
}
catch (Exception ex)
{
Logger.Log($"Failed to start DNS proxy: {ex.Message}", LogLevel.WARNING);
_proxyRunning = false;
}
}
private static void StopProxy()
{
_proxyRunning = false;
_proxyCts?.Cancel();
try { _proxyListener?.Stop(); } catch { }
}
private static async Task ProxyAcceptLoop(CancellationToken ct)
{
while (!ct.IsCancellationRequested && _proxyRunning)
{
try
{
var client = await _proxyListener.AcceptTcpClientAsync();
_ = HandleProxyClient(client, ct);
}
catch (ObjectDisposedException) { break; }
catch (Exception ex)
{
if (!ct.IsCancellationRequested)
Logger.Log($"Proxy accept error: {ex.Message}", LogLevel.WARNING);
}
}
}
private static async Task HandleProxyClient(TcpClient client, CancellationToken ct)
{
try
{
using (client)
using (var stream = client.GetStream())
{
client.ReceiveTimeout = client.SendTimeout = 30000;
var buffer = new byte[8192];
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, ct);
if (bytesRead == 0) return;
string request = Encoding.ASCII.GetString(buffer, 0, bytesRead);
string[] lines = request.Split(new[] { "\r\n" }, StringSplitOptions.None);
if (lines.Length == 0) return;
string[] requestLine = lines[0].Split(' ');
if (requestLine.Length < 2) return;
if (requestLine[0] == "CONNECT")
// HTTPS proxy - tunnel mode
await HandleConnectRequest(stream, requestLine[1], ct);
else
// HTTP proxy - forward mode
await HandleHttpRequest(stream, request, requestLine[1], ct);
}
}
catch (Exception ex)
{
if (!ct.IsCancellationRequested)
Logger.Log($"Proxy client error: {ex.Message}", LogLevel.WARNING);
}
}
private static async Task HandleConnectRequest(NetworkStream clientStream, string target, CancellationToken ct)
{
// Parse host:port
string[] parts = target.Split(':');
string host = parts[0];
int port = parts.Length > 1 && int.TryParse(parts[1], out int p) ? p : 443;
// Resolve hostname
IPAddress ip = ResolveHostname(host, alwaysTryFallback: true);
if (ip == null)
{
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
return;
}
try
{
// Connect to target
using (var targetClient = new TcpClient())
{
await targetClient.ConnectAsync(ip, port);
using (var targetStream = targetClient.GetStream())
{
// Send 200 OK to client
await SendResponse(clientStream, "HTTP/1.1 200 Connection Established\r\n\r\n", ct);
// Tunnel data bidirectionally
await Task.WhenAny(RelayData(clientStream, targetStream, ct), RelayData(targetStream, clientStream, ct));
}
}
}
catch (Exception ex)
{
Logger.Log($"CONNECT tunnel error to {host}: {ex.Message}", LogLevel.WARNING);
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
}
}
private static async Task HandleHttpRequest(NetworkStream clientStream, string request, string url, CancellationToken ct)
{
try
{
var uri = new Uri(url);
IPAddress ip = ResolveHostname(uri.Host, alwaysTryFallback: true);
if (ip == null)
{
await SendResponse(clientStream, "HTTP/1.1 502 Bad Gateway\r\n\r\n", ct);
return;
}
using (var targetClient = new TcpClient())
{
await targetClient.ConnectAsync(ip, uri.Port > 0 ? uri.Port : 80);
using (var targetStream = targetClient.GetStream())
{
// Modify request to use relative path
string modifiedRequest = request.Replace(url, uri.PathAndQuery);
byte[] requestBytes = Encoding.ASCII.GetBytes(modifiedRequest);
await targetStream.WriteAsync(requestBytes, 0, requestBytes.Length, ct);
// Relay response
await RelayData(targetStream, clientStream, ct);
}
}
}
catch (Exception ex)
{
Logger.Log($"HTTP proxy error: {ex.Message}", LogLevel.WARNING);
}
}
private static async Task SendResponse(NetworkStream stream, string response, CancellationToken ct)
{
byte[] bytes = Encoding.ASCII.GetBytes(response);
try { await stream.WriteAsync(bytes, 0, bytes.Length, ct); } catch { }
}
private static async Task RelayData(NetworkStream from, NetworkStream to, CancellationToken ct)
{
byte[] buffer = new byte[8192];
try
{
int bytesRead;
while ((bytesRead = await from.ReadAsync(buffer, 0, buffer.Length, ct)) > 0)
await to.WriteAsync(buffer, 0, bytesRead, ct);
}
catch { }
}
}
}

View File

@@ -1,91 +0,0 @@
using System;
using System.IO;
using System.Threading;
namespace AndroidSideloader.Utilities
{
internal static class FileSystemUtilities
{
public static bool TryDeleteDirectory(string directoryPath, int maxRetries = 3, int delayMs = 150) // 3x 150ms = 450ms total
{
if (string.IsNullOrWhiteSpace(directoryPath))
return true;
if (!Directory.Exists(directoryPath))
return true;
Exception lastError = null;
// Retry deletion several times in case of lock ups
for (int attempt = 0; attempt <= maxRetries; attempt++)
{
try
{
StripReadOnlyAttributes(directoryPath);
Directory.Delete(directoryPath, true);
return true;
}
catch (DirectoryNotFoundException)
{
return true;
}
catch (Exception ex) when (ex is UnauthorizedAccessException || ex is IOException)
{
lastError = ex;
if (attempt < maxRetries)
{
Thread.Sleep(delayMs);
continue;
}
break;
}
catch (Exception ex)
{
// Non-retryable error
lastError = ex;
break;
}
}
// Last resort: rename then delete
try
{
string renamedPath = directoryPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
+ ".deleting." + DateTime.UtcNow.Ticks;
Directory.Move(directoryPath, renamedPath);
StripReadOnlyAttributes(renamedPath);
Directory.Delete(renamedPath, true);
return true;
}
catch (Exception ex)
{
lastError = ex;
}
Logger.Log($"Failed to delete directory: {directoryPath}. Error: {lastError}", LogLevel.WARNING);
return false;
}
private static void StripReadOnlyAttributes(string directoryPath)
{
var root = new DirectoryInfo(directoryPath);
if (!root.Exists) return;
root.Attributes &= ~FileAttributes.ReadOnly;
foreach (var dir in root.EnumerateDirectories("*", SearchOption.AllDirectories))
{
dir.Attributes &= ~FileAttributes.ReadOnly;
}
foreach (var file in root.EnumerateFiles("*", SearchOption.AllDirectories))
{
file.Attributes &= ~FileAttributes.ReadOnly;
}
}
}
}

View File

@@ -1,13 +1,18 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Diagnostics;
using JR.Utils.GUI.Forms;
using System.Net;
using System.Windows.Forms;
using System.Net.Http;
using System.IO;
using AndroidSideloader;
using System.Linq;
namespace AndroidSideloader.Utilities
{
internal class GeneralUtilities
class GeneralUtilities
{
public static long GetDirectorySize(string folderPath)
{
@@ -19,20 +24,19 @@ namespace AndroidSideloader.Utilities
{
return $"com.{GeneralUtilities.randomString(rand.Next(3, 8))}.{GeneralUtilities.randomString(rand.Next(3, 8))}";
}
bool isLoading = true;
public static string CommandOutput = "";
public static string CommandError = "";
public static void ExecuteCommand(string command)
{
ProcessStartInfo processInfo = new ProcessStartInfo("cmd.exe", "/c " + command)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true
};
var processInfo = new ProcessStartInfo("cmd.exe", "/c " + command);
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
Process process = Process.Start(processInfo);
var process = Process.Start(processInfo);
process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
CommandOutput += e.Data;
@@ -44,12 +48,13 @@ namespace AndroidSideloader.Utilities
process.WaitForExit();
Console.WriteLine("ExitCode: {0}", process.ExitCode);
process.Close();
}
public static void Melt()
{
_ = Process.Start(new ProcessStartInfo()
Process.Start(new ProcessStartInfo()
{
Arguments = "/C choice /C Y /N /D Y /T 5 & Del \"" + Application.ExecutablePath + "\"",
WindowStyle = ProcessWindowStyle.Hidden,
@@ -58,8 +63,7 @@ namespace AndroidSideloader.Utilities
});
Environment.Exit(0);
}
private static readonly Random rand = new Random();
static Random rand = new Random();
public static string randomString(int length)
{
string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -68,7 +72,7 @@ namespace AndroidSideloader.Utilities
int randomInteger = rand.Next(0, valid.Length);
while (0 < length--)
{
_ = res.Append(valid[randomInteger]);
res.Append(valid[randomInteger]);
randomInteger = rand.Next(0, valid.Length);
}
return res.ToString();
@@ -76,7 +80,7 @@ namespace AndroidSideloader.Utilities
public static ProcessOutput startProcess(string process, string path, string command)
{
_ = Logger.Log($"Ran process {process} with command {command} in path {path}");
Logger.Log($"Ran process {process} with command {command} in path {path}");
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
@@ -85,17 +89,38 @@ namespace AndroidSideloader.Utilities
cmd.StartInfo.WorkingDirectory = path;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
_ = cmd.Start();
cmd.Start();
cmd.StandardInput.WriteLine(command);
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
string error = cmd.StandardError.ReadToEnd();
string output = cmd.StandardOutput.ReadToEnd();
_ = Logger.Log($"Output: {output}");
_ = Logger.Log($"Error: {error}", LogLevel.ERROR);
return new ProcessOutput(output, error);
Logger.Log($"Output: {output}");
Logger.Log($"Error: {error}");
return new ProcessOutput(output,error);
}
}
class Zip
{
public static void ExtractFile(string sourceArchive, string destination)
{
if (!File.Exists(Environment.CurrentDirectory + "\\7z.exe"))
{
WebClient client = new WebClient();
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/7z.exe", "7z.exe");
client.DownloadFile("https://github.com/nerdunit/androidsideloader/raw/master/7z.dll", "7z.dll");
}
ProcessStartInfo pro = new ProcessStartInfo();
pro.WindowStyle = ProcessWindowStyle.Hidden;
pro.FileName = "7z.exe";
pro.Arguments = string.Format("x \"{0}\" -y -o\"{1}\"", sourceArchive, destination);
Process x = Process.Start(pro);
x.WaitForExit();
}
}
}

View File

@@ -1,110 +1,18 @@
using AndroidSideloader.Utilities;
using System;
using System.IO;
using System.Text;
namespace AndroidSideloader
{
public enum LogLevel
{
DEBUG,
INFO,
WARNING,
ERROR,
TRACE,
FATAL
}
public static class Logger
{
private static readonly SettingsManager settings = SettingsManager.Instance;
private static readonly object lockObject = new object();
private static string logFilePath = settings.CurrentLogPath;
public static void Initialize()
{
try
{
// Set default log path if not already set
if (string.IsNullOrEmpty(logFilePath))
{
logFilePath = Path.Combine(Environment.CurrentDirectory, "debuglog.txt");
}
// Create directory if it doesn't exist
string logDirectory = Path.GetDirectoryName(logFilePath);
if (!string.IsNullOrEmpty(logDirectory) && !Directory.Exists(logDirectory))
{
Directory.CreateDirectory(logDirectory);
}
// Create log file if it doesn't exist
if (!File.Exists(logFilePath))
{
using (FileStream fs = File.Create(logFilePath))
{
// Create empty file
}
}
// Update settings with log path
settings.CurrentLogPath = logFilePath;
settings.Save();
// Initial log entry, make it stand out
string time = DateTime.UtcNow.ToString("hh:mm:ss.fff tt (UTC): ");
Log($"\n\n{time}------------ Logger initialized ------------", LogLevel.INFO);
}
catch (Exception ex)
{
Console.WriteLine($"Error initializing logger: {ex.Message}");
}
}
public static bool Log(string text, LogLevel logLevel = LogLevel.INFO, bool ret = true)
{
if (string.IsNullOrWhiteSpace(text) || text.Length <= 5)
return ret;
// Initialize logger if not already initialized
if (string.IsNullOrEmpty(logFilePath))
{
Initialize();
}
string time = DateTime.UtcNow.ToString("hh:mm:ss.fff tt (UTC): ");
string newline = text.Length > 40 && text.Contains("\n") ? "\n\n" : "\n";
string logEntry = time + "[" + logLevel.ToString().ToUpper() + "] [" + GetCallerInfo() + "] " + text + newline;
try
{
lock (lockObject)
{
File.AppendAllText(logFilePath, logEntry);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error writing to log: {ex.Message}");
}
return ret;
}
private static string GetCallerInfo()
{
System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(true);
if (stackTrace.FrameCount >= 3)
{
var frame = stackTrace.GetFrame(2);
var method = frame.GetMethod();
string className = method.DeclaringType?.Name;
string methodName = method.Name;
string callerInfo = $"{className}.{methodName}";
return callerInfo;
}
return string.Empty;
}
}
}
using System.IO;
namespace AndroidSideloader
{
class Logger
{
public static string logfile = "debuglog.txt";
public static bool Log(string text, bool ret = true)
{
string newline = "\n";
if (text.Length > 40 && text.Contains("\n"))
newline += "\n\n";
try { File.AppendAllText(logfile, text + newline); } catch { }
return ret;
}
}
}

View File

@@ -1,81 +0,0 @@
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace AndroidSideloader.Utilities
{
internal class Metrics
{
public static async void CountDownload(string packageName, string versionCode)
{
try
{
var apiUrl = "https://api.vrpirates.wiki/metrics/add";
var requestBody = new
{
packagename = packageName,
versioncode = versionCode
};
var json = JsonConvert.SerializeObject(requestBody);
string res = await Task.Run(() => sendToApi(apiUrl, json, "post"));
_ = Logger.Log(res);
}
catch (Exception ex)
{
Logger.Log($"Unable to log download: {ex.Message}", LogLevel.WARNING);
}
}
private static async Task<string> sendToApi(string apiUrl, string requestBody = null, string type = "get")
{
string token = "cm9va2llOkN0UHlyTE9oUGoxWXg1cE9KdDNBSkswZ25n";
using (var client = new HttpClient())
{
var request = new HttpRequestMessage();
// Set the HTTP method
request.Method = type.ToLower() == "post" ? HttpMethod.Post : HttpMethod.Get;
// For GET requests with parameters, append them to the URL
if (request.Method == HttpMethod.Get && !string.IsNullOrEmpty(requestBody))
{
var uriBuilder = new UriBuilder(apiUrl);
uriBuilder.Query = requestBody;
request.RequestUri = uriBuilder.Uri;
}
else
{
request.RequestUri = new Uri(apiUrl);
}
// For POST requests, set the content
if (request.Method == HttpMethod.Post && !string.IsNullOrEmpty(requestBody))
{
request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
}
// Add headers to the request
request.Headers.Add("Authorization", token);
request.Headers.Add("Origin", "rookie");
string responseContent = "";
try
{
HttpResponseMessage response = await client.SendAsync(request);
responseContent = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
Logger.Log($"Unable to get Metrics Data: {ex.Message}", LogLevel.WARNING);
}
return responseContent;
}
}
}
}

View File

@@ -1,332 +0,0 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
namespace AndroidSideloader.Utilities
{
public class SettingsManager : IDisposable
{
private static readonly Lazy<SettingsManager> _instance = new Lazy<SettingsManager>(() => new SettingsManager());
private static readonly string settingsFilePath = Path.Combine(
Environment.CurrentDirectory,
"settings.json");
// Custom converters for special types
public class FontConverter : JsonConverter<Font>
{
public override Font ReadJson(JsonReader reader, Type objectType, Font existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var jo = JObject.Load(reader);
string fontFamily = jo["FontFamily"]?.Value<string>() ?? "Microsoft Sans Serif";
float fontSize = jo["Size"]?.Value<float>() ?? 11.25f;
return new Font(fontFamily, fontSize);
}
public override void WriteJson(JsonWriter writer, Font value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("FontFamily");
writer.WriteValue(value.FontFamily.Name);
writer.WritePropertyName("Size");
writer.WriteValue(value.Size);
writer.WriteEndObject();
}
}
public class ColorConverter : JsonConverter<Color>
{
public override Color ReadJson(JsonReader reader, Type objectType, Color existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var jo = JObject.Load(reader);
int a = jo["A"]?.Value<int>() ?? 255;
int r = jo["R"]?.Value<int>() ?? 0;
int g = jo["G"]?.Value<int>() ?? 0;
int b = jo["B"]?.Value<int>() ?? 0;
return Color.FromArgb(a, r, g, b);
}
public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("A");
writer.WriteValue(value.A);
writer.WritePropertyName("R");
writer.WriteValue(value.R);
writer.WritePropertyName("G");
writer.WriteValue(value.G);
writer.WritePropertyName("B");
writer.WriteValue(value.B);
writer.WriteEndObject();
}
}
[JsonConverter(typeof(FontConverter))]
public Font FontStyle { get; set; } = new Font("Microsoft Sans Serif", 11.25f);
[JsonConverter(typeof(FontConverter))]
public Font BigFontStyle { get; set; } = new Font("Microsoft Sans Serif", 14f);
[JsonConverter(typeof(ColorConverter))]
public Color FontColor { get; set; } = Color.White;
[JsonConverter(typeof(ColorConverter))]
public Color ComboBoxColor { get; set; } = Color.FromArgb(25, 25, 25);
[JsonConverter(typeof(ColorConverter))]
public Color SubButtonColor { get; set; } = Color.FromArgb(25, 25, 25);
[JsonConverter(typeof(ColorConverter))]
public Color TextBoxColor { get; set; } = Color.FromArgb(25, 25, 25);
[JsonConverter(typeof(ColorConverter))]
public Color ButtonColor { get; set; } = Color.Black;
[JsonConverter(typeof(ColorConverter))]
public Color BackColor { get; set; } = Color.FromArgb(1, 1, 1);
public bool CheckForUpdates { get; set; } = true;
public bool EnableMessageBoxes { get; set; } = true;
public bool FirstRun { get; set; } = true;
public bool DeleteAllAfterInstall { get; set; } = true;
public bool AutoUpdateConfig { get; set; } = true;
public bool UserJsonOnGameInstall { get; set; } = false;
public bool CallUpgrade { get; set; } = true;
public string BackPicturePath { get; set; } = string.Empty;
public bool SpoofGames { get; set; } = false;
public bool ResignAPKs { get; set; } = false;
public string IPAddress { get; set; } = string.Empty;
public string InstalledApps { get; set; } = string.Empty;
public string ADBPath { get; set; } = string.Empty;
public string MainDir { get; set; } = string.Empty;
public bool Delsh { get; set; } = false;
public string CurrPckg { get; set; } = string.Empty;
public string ADBFolder { get; set; } = string.Empty;
public bool WirelessADB { get; set; } = false;
public string CurrentGamename { get; set; } = string.Empty;
public bool PackageNameToCB { get; set; } = false;
public bool DownUpHeld { get; set; } = false;
public string CurrentLogPath { get; set; } = string.Empty;
public string CurrentLogName { get; set; } = string.Empty;
public string CurrentCrashPath { get; set; } = string.Empty;
public string CurrentCrashName { get; set; } = string.Empty;
public bool AdbDebugWarned { get; set; } = false;
public bool NodeviceMode { get; set; } = false;
public bool BMBFChecked { get; set; } = true;
public string GamesList { get; set; } = string.Empty;
public bool UploadedGameList { get; set; } = false;
public string GlobalUsername { get; set; } = string.Empty;
public DateTime LastTimeShared { get; set; } = new DateTime(1969, 4, 20, 16, 20, 0);
public bool AutoReinstall { get; set; } = false;
public string NonAppPackages { get; set; } = string.Empty;
public DateTime LastLaunch { get; set; } = new DateTime(1969, 4, 20, 16, 20, 0);
public string SubmittedUpdates { get; set; } = string.Empty;
public bool ListUpped { get; set; } = false;
public DateTime LastLaunch2 { get; set; } = new DateTime(1969, 4, 20, 16, 20, 0);
public bool Wired { get; set; } = false;
public string AppPackages { get; set; } = string.Empty;
public string DownloadDir { get; set; } = string.Empty;
public bool CustomDownloadDir { get; set; } = false;
public bool CustomBackupDir { get; set; } = false;
public string BackupDir { get; set; } = string.Empty;
public bool SingleThreadMode { get; set; } = true;
public bool VirtualFilesystemCompatibility { get; set; } = false;
public bool UpdateSettings { get; set; } = true;
public string UUID { get; set; } = Guid.NewGuid().ToString();
public bool CreatePubMirrorFile { get; set; } = true;
public bool UseDownloadedFiles { get; set; } = false;
public float BandwidthLimit { get; set; } = 0f;
public string[] FavoritedGames { get; set; } = new string[0];
public bool useProxy { get; set; } = false;
public string ProxyAddress { get; set; } = string.Empty;
public string ProxyPort { get; set; } = string.Empty;
public string selectedMirror { get; set; } = string.Empty;
public bool TrailersEnabled { get; set; } = true;
public bool UseGalleryView { get; set; } = true;
// Window state persistence
public int WindowX { get; set; } = -1;
public int WindowY { get; set; } = -1;
public int WindowWidth { get; set; } = -1;
public int WindowHeight { get; set; } = -1;
public bool WindowMaximized { get; set; } = false;
// Sort state persistence
public int SortColumn { get; set; } = 0;
public bool SortAscending { get; set; } = true;
// Download queue persistence
public string[] QueuedGames { get; set; } = new string[0];
private SettingsManager()
{
Load();
Save();
}
public static SettingsManager Instance => _instance.Value;
public void Save()
{
try
{
var settings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var json = JsonConvert.SerializeObject(this, settings);
File.WriteAllText(settingsFilePath, json);
}
catch (Exception ex)
{
Console.WriteLine($"Error saving settings: {ex.Message}");
}
}
private void Load()
{
Debug.WriteLine("Loading settings...");
if (!File.Exists(settingsFilePath))
{
CreateDefaultSettings();
return;
}
try
{
var json = File.ReadAllText(settingsFilePath);
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
Debug.WriteLine($"Error deserializing setting: {args.ErrorContext.Error.Message}");
args.ErrorContext.Handled = true;
}
};
JsonConvert.PopulateObject(json, this, settings);
}
catch (Exception ex)
{
Debug.WriteLine($"Error loading settings: {ex.Message}");
CreateDefaultSettings();
}
}
private void CreateDefaultSettings()
{
FontStyle = new Font("Microsoft Sans Serif", 11.25f);
BigFontStyle = new Font("Microsoft Sans Serif", 14f);
FontColor = Color.White;
ComboBoxColor = Color.FromArgb(25, 25, 25);
SubButtonColor = Color.FromArgb(25, 25, 25);
TextBoxColor = Color.FromArgb(25, 25, 25);
ButtonColor = Color.Black;
BackColor = Color.FromArgb(1, 1, 1);
CheckForUpdates = true;
EnableMessageBoxes = true;
FirstRun = true;
DeleteAllAfterInstall = true;
AutoUpdateConfig = true;
UserJsonOnGameInstall = false;
CallUpgrade = true;
BackPicturePath = string.Empty;
SpoofGames = false;
ResignAPKs = false;
IPAddress = string.Empty;
InstalledApps = string.Empty;
ADBPath = string.Empty;
MainDir = string.Empty;
Delsh = false;
CurrPckg = string.Empty;
ADBFolder = string.Empty;
WirelessADB = false;
CurrentGamename = string.Empty;
PackageNameToCB = false;
DownUpHeld = false;
CurrentLogPath = string.Empty;
CurrentLogName = string.Empty;
CurrentCrashPath = string.Empty;
CurrentCrashName = string.Empty;
AdbDebugWarned = false;
NodeviceMode = false;
BMBFChecked = true;
GamesList = string.Empty;
UploadedGameList = false;
GlobalUsername = string.Empty;
LastTimeShared = new DateTime(1969, 4, 20, 16, 20, 0);
AutoReinstall = false;
NonAppPackages = string.Empty;
LastLaunch = new DateTime(1969, 4, 20, 16, 20, 0);
SubmittedUpdates = string.Empty;
ListUpped = false;
LastLaunch2 = new DateTime(1969, 4, 20, 16, 20, 0);
Wired = false;
AppPackages = string.Empty;
DownloadDir = string.Empty;
CustomDownloadDir = false;
CustomBackupDir = false;
BackupDir = string.Empty;
SingleThreadMode = true;
VirtualFilesystemCompatibility = false;
UpdateSettings = true;
UUID = Guid.NewGuid().ToString();
CreatePubMirrorFile = true;
UseDownloadedFiles = false;
BandwidthLimit = 0f;
FavoritedGames = new string[0];
useProxy = false;
ProxyAddress = string.Empty;
ProxyPort = string.Empty;
selectedMirror = string.Empty;
TrailersEnabled = true;
UseGalleryView = true;
WindowX = -1;
WindowY = -1;
WindowWidth = -1;
WindowHeight = -1;
WindowMaximized = false;
SortColumn = 0;
SortAscending = true;
QueuedGames = new string[0];
Save();
Debug.WriteLine("Default settings created.");
}
public void AddFavoriteGame(string packageName)
{
if (!FavoritedGames.Contains(packageName))
{
var list = FavoritedGames.ToList();
list.Add(packageName);
FavoritedGames = list.ToArray();
Save();
}
}
public void RemoveFavoriteGame(string packageName)
{
if (FavoritedGames.Contains(packageName))
{
var list = FavoritedGames.ToList();
list.Remove(packageName);
FavoritedGames = list.ToArray();
Save();
}
}
public string GetEffectiveBackupDir()
{
if (CustomBackupDir && Directory.Exists(BackupDir))
{
return BackupDir;
}
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Rookie Backups");
}
public void Dispose()
{
FontStyle?.Dispose();
BigFontStyle?.Dispose();
}
}
}

View File

@@ -1,17 +1,18 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AndroidSideloader.Utilities
{
internal class StringUtilities
class StringUtilities
{
public static string RemoveEverythingAfterFirst(string s, string removeMe)
{
int index = s.IndexOf(removeMe);
if (index > 0)
{
s = s.Substring(0, index);
}
return s;
}
@@ -19,10 +20,7 @@ namespace AndroidSideloader.Utilities
{
int index = s.LastIndexOf(removeMe);
if (index > 0)
{
s = s.Substring(0, index);
}
return s;
}
@@ -30,10 +28,7 @@ namespace AndroidSideloader.Utilities
{
int index = s.IndexOf(removeMe);
if (index > 0)
{
s = s.Substring(index);
}
return s;
}
@@ -55,19 +50,8 @@ namespace AndroidSideloader.Utilities
{
int index = s.LastIndexOf(removeMe);
if (index > 0)
{
s = s.Substring(index);
}
return s;
}
public static bool TryParseDouble(string value, out double result)
{
return double.TryParse(value,
System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.InvariantCulture,
out result);
}
}
}

View File

@@ -1,16 +0,0 @@
namespace AndroidSideloader.Utilities
{
internal class UpdateGameData
{
public UpdateGameData(string gameName, string packageName, ulong installedVersionInt)
{
GameName = gameName;
Packagename = packageName;
InstalledVersionInt = installedVersionInt;
}
public string GameName { get; set; }
public string Packagename { get; set; }
public ulong InstalledVersionInt { get; set; }
}
}

View File

@@ -1,25 +0,0 @@
namespace AndroidSideloader.Utilities
{
internal class UploadGame
{
public UploadGame(string Uploadcommand, string Pckgcommand, string Uploadgamename, ulong Uploadversion, bool isUpdate)
{
this.Pckgcommand = Pckgcommand;
this.Uploadgamename = Uploadgamename;
this.Uploadversion = Uploadversion;
this.isUpdate = isUpdate;
}
public UploadGame()
{
}
public bool isUpdate { get; set; }
public string Pckgcommand { get; set; }
public string Uploadgamename { get; set; }
public ulong Uploadversion { get; set; }
}
}

View File

@@ -1,220 +0,0 @@
using JR.Utils.GUI.Forms;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace AndroidSideloader.Utilities
{
public class ExtractionException : Exception
{
public ExtractionException(string message) : base(message) { }
}
internal class Zip
{
private static readonly SettingsManager settings = SettingsManager.Instance;
// Progress callback: (percent, eta)
public static Action<float, TimeSpan?> ExtractionProgressCallback { get; set; }
public static Action<string> ExtractionStatusCallback { get; set; }
public static void ExtractFile(string sourceArchive, string destination)
{
string args = $"x \"{sourceArchive}\" -y -o\"{destination}\" -bsp1";
DoExtract(args);
}
public static void ExtractFile(string sourceArchive, string destination, string password)
{
string args = $"x \"{sourceArchive}\" -y -o\"{destination}\" -p\"{password}\" -bsp1";
DoExtract(args);
}
private static string extractionError = null;
private static bool errorMessageShown = false;
private static void DoExtract(string args)
{
if (!File.Exists(Path.Combine(Environment.CurrentDirectory, "7z.exe")) || !File.Exists(Path.Combine(Environment.CurrentDirectory, "7z.dll")))
{
_ = Logger.Log("Begin download 7-zip");
string architecture = Environment.Is64BitOperatingSystem ? "64" : "";
try
{
// Use DNS fallback download method from GetDependencies
GetDependencies.DownloadFileWithDnsFallback($"https://github.com/VRPirates/rookie/raw/master/7z{architecture}.exe", "7z.exe");
GetDependencies.DownloadFileWithDnsFallback($"https://github.com/VRPirates/rookie/raw/master/7z{architecture}.dll", "7z.dll");
}
catch (Exception ex)
{
_ = FlexibleMessageBox.Show(Program.form, $"You are unable to access the GitHub page with the Exception: {ex.Message}\nSome files may be missing (7z)");
_ = FlexibleMessageBox.Show(Program.form, "7z was unable to be downloaded\nRookie will now close");
Application.Exit();
}
_ = Logger.Log("Complete download 7-zip");
}
ProcessStartInfo pro = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "7z.exe",
Arguments = args,
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true
};
_ = Logger.Log($"Extract: 7z {string.Join(" ", args.Split(' ').Where(a => !a.StartsWith("-p")))}");
// Throttle percent reports
float lastReportedPercent = -1;
// ETA engine (percent units)
var etaEstimator = new EtaEstimator(alpha: 0.10, reanchorThreshold: 0.20, minSampleSeconds: 0.10);
// Smooth progress (sub-percent) interpolation (because 7z -bsp1 is integer-only)
System.Threading.Timer smoothTimer = null;
int extractingFlag = 1; // 1 = extracting, 0 = stop
float smoothLastTickPercent = 0f;
DateTime smoothLastTickTime = DateTime.UtcNow;
float smoothLastReported = -1f;
const int SmoothIntervalMs = 80; // ~12.5 updates/sec
const float SmoothReportDelta = 0.10f; // report only if change >= 0.10%
using (Process x = new Process())
{
x.StartInfo = pro;
if (MainForm.isInDownloadExtract && x != null)
{
// Smooth sub-percent UI, while keeping ETA ticking
smoothTimer = new System.Threading.Timer(_ =>
{
if (System.Threading.Volatile.Read(ref extractingFlag) == 0) return;
if (smoothLastTickPercent <= 0) return; // need at least one 7z tick
// Use current ETA to approximate seconds-per-percent
TimeSpan? displayEta = etaEstimator.GetDisplayEta();
if (!displayEta.HasValue) return; // Skip until ETA exists
var now = DateTime.UtcNow;
var elapsed = (now - smoothLastTickTime).TotalSeconds;
// Approx seconds-per-percent from remaining ETA / remaining percent
double remainingPercent = Math.Max(1.0, 100.0 - smoothLastTickPercent);
double spp = Math.Max(0.05, displayEta.Value.TotalSeconds / remainingPercent);
float candidate = smoothLastTickPercent + (float)(elapsed / spp);
// Clamp
float floorTick = (float)Math.Floor(smoothLastTickPercent);
float ceiling = Math.Min(99.99f, floorTick + 0.999f);
if (candidate > ceiling) candidate = ceiling;
if (candidate < smoothLastTickPercent) candidate = smoothLastTickPercent;
if (smoothLastReported >= 0 && Math.Abs(candidate - smoothLastReported) < SmoothReportDelta) return;
smoothLastReported = candidate;
try
{
MainForm mainForm = (MainForm)Application.OpenForms[0];
if (mainForm != null && !mainForm.IsDisposed)
{
mainForm.BeginInvoke((Action)(() => mainForm.SetProgress(candidate)));
}
}
catch { }
// ETA countdown ticks even if 7z percent is unchanged
ExtractionProgressCallback?.Invoke(candidate, etaEstimator.GetDisplayEta());
}, null, SmoothIntervalMs, SmoothIntervalMs);
x.OutputDataReceived += (sender, e) =>
{
if (e.Data != null)
{
var match = Regex.Match(e.Data, @"^\s*(\d+)%");
if (match.Success && float.TryParse(match.Groups[1].Value, out float percent))
{
// Update ETA from integer percent
if (percent <= 0.0f) etaEstimator.Reset();
else if (percent < 100.0f) etaEstimator.Update(totalUnits: 100, doneUnits: (long)Math.Round(percent));
// Reset smoothing baseline on each integer tick
smoothLastTickPercent = percent;
smoothLastTickTime = DateTime.UtcNow;
smoothLastReported = percent;
if (Math.Abs(percent - lastReportedPercent) >= 0.1f)
{
lastReportedPercent = percent;
MainForm mainForm = (MainForm)Application.OpenForms[0];
if (mainForm != null)
{
mainForm.Invoke((Action)(() => mainForm.SetProgress(percent)));
}
ExtractionProgressCallback?.Invoke(percent, etaEstimator.GetDisplayEta());
}
}
}
};
}
x.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null)
{
var error = e.Data;
if (error.Contains("There is not enough space on the disk") && !errorMessageShown)
{
errorMessageShown = true;
Program.form.Invoke(new Action(() =>
{
_ = FlexibleMessageBox.Show(Program.form, $"Not enough space to extract archive.\r\nMake sure your {Path.GetPathRoot(settings.DownloadDir)} drive has at least double the space of the game, then try again.",
"NOT ENOUGH SPACE",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
return;
}));
}
_ = Logger.Log(error, LogLevel.ERROR);
extractionError = $"Extracting failed: {error}"; // Store the error message directly
return;
}
};
x.Start();
x.BeginOutputReadLine();
x.BeginErrorReadLine();
x.WaitForExit();
// Stop smoother
System.Threading.Interlocked.Exchange(ref extractingFlag, 0);
smoothTimer?.Dispose();
smoothTimer = null;
// Clear callbacks
ExtractionProgressCallback?.Invoke(100, null);
ExtractionStatusCallback?.Invoke("");
errorMessageShown = false;
if (!string.IsNullOrEmpty(extractionError))
{
string errorMessage = extractionError;
extractionError = null; // Reset the error message
throw new ExtractionException(errorMessage);
}
}
}
}
}

View File

@@ -1,22 +0,0 @@
@echo off
REM Default to Release if no argument is provided
SET CONFIG=Release
IF NOT "%1"=="" (
IF /I "%1"=="debug" SET CONFIG=Debug
)
REM Windows Batch script version
REM Attempts to find MSBuild from common Visual Studio 2022 installation paths
IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" (
SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe"
) ELSE IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe" (
SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\MSBuild.exe"
) ELSE IF EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe" (
SET MSBUILD="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\MSBuild.exe"
) ELSE (
echo MSBuild not found! Please check your Visual Studio installation.
exit /b 1
)
echo Building in %CONFIG% configuration...
%MSBUILD% AndroidSideloader.sln /t:AndroidSideloader /p:Configuration=%CONFIG%

View File

@@ -1,12 +1,552 @@
RSL 3.0.1
!!!IMPORTANT!!!
THIS VERSION IS WORK IN PROGRESS DUE TO LACK OF TESTERS!
Due to how the rclone config works now, if you used Rookie's Sideloader with a custom config
Make sure to redownload the entire rclone folder from the config provider!
- Fixed popularity ranking not working on some systems
- Fixed favorites not updating immediately when removing items
- Improved YouTube trailer matching accuracy
- Implemented real-time progress updates for drag and drop operations
- Refined backup button labels and dialogs
- Gallery View: Added grouped tiles for games with multiple versions (e.g. Beat Saber)
- ListView: Uninstall button now shows on hover instead of click
- Public config file is now created automatically without prompt
- Sideloading status label now shows device connection state
- Download button text now reflects sideloading status
v2.0-WIP
Changes
+ Added update checker for games
+ Added dependency check for spoofer
+ Games now can have images
+ Replaced the gamescombo box with a listview
+ Listview marks already installed games with green and outdated ones with yellow
+ Sideloader should be faster now
+ Reduced sideloader size
+ Installing games and copying obbs tries to wake the device first
+ Sideloader calls adb usb on start now
+ ADB Output now is a proper object containing strings for stdout and stderr, handling will be easier now
+ Changed spoof on rclone install to resign, allowing users to easily update games from now on!
//You can still use the spoof button manually
= Fixed UI not starting for some people
= Refreshing mirrors now deosn't change the selected mirror
= Cleaned & reworked code in sideloader and spoofer
= Fixed Spoofer.Init() on Non-English Windows
= Fixed crash detection
= Reworked rclone config handling
= Fixed game release not existing resulted in a crash
= Sideloader false positive detections reduced
= Small ui changes, hopefully for the better
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.17SU1
Changes
+ Added some instructions & checks for the spoofer
+ Added crash detection
= Fixed the game queue broken since 1.17
Date 11/19/2020
VT: https://bit.ly/3nDUMcx
MD5 Checksum: 6DA8ADBE4447A809C598379E73DC7F77
SHA-1 Checksum: 924220FE8877174CCB9732F1F99B759DD6749102
SHA-256 Checksum: 0405C389A7D84CAC0D9081BDE10D010300822B10EBC2FF94C501EC740C8CFA40
SHA-512 Checksum: E8C3A15257C30278CEBC46507B1F6049FFB5AC0D6E4FBB73E1776537F80CBEA95C8C81A3F3259F8AEEDE276EBF6D50F6945622403E9D80B5E9E0F47B050BBEA9
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+2aycACgkQvrtJUNxE
TxOlEw/6ArmiRFAjUNC2YaElJ7fFsXVzCaeJ680rs0CK4oX9P7YjZ46y2/VGDtX/
IAGvWCqHOIw2t0sk01/JwoyKZFERLDn2MRCj9FTPsrPA8yqveiIx/fof90QaN2Q9
4aV6ht+SSirQFWTXENboEbQSWxFHW/z5/Dud8gDBuCTuFuueBk+EAph5yI3dcjCK
naDE1gX+CE21ef84F3nGMspu2q/uCaIM2mvEWR2hBvWLsQpH7m5uQegXGYywe6YC
/8wEY2mEe0nayp/3NglDDarsPN8wx1U5i/kqS8wrzZZT49pRqKZ0wykWGfAPQsaO
txmfiwH+5cu3J/6PpAMVuNjhtL0dnR5MapsXT3CoRvSiRDl2urdYJUQj1CsYOEWP
Q4St6ISoUoANhVFRcM9mbq7clxdJnfBqdr1J0YrK804qWp3krDYv5hrpE3Puu/nA
TORsqWiHPgQQHANsNYsY4WkvLiYHWyB62Cm2NATdtaoVWzsrBgFk9xlp1oIQcMXo
RlRQZQ7tQ0VFFxaP7ARRaf9ay78geC3W/cr63JTn8Hz7Ul1h+ZRa7tb1KYvpCTnp
xC7vh3IyBwc4M7mt4CxsjdFnkO3iaDybFvlufua/5vMlt70HLdutHa7vMYSZ+GFr
HL+SrazP9o8ut2L85uBqCjWHPfgVaBaaQgk9FgZe0WQoS06fdeU=
=DIzT
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.17
Please manually update to this version, as it fixes automatic updates that were broken since 1.15
Changes
+ Better game installation => no need for manual installation of games anymore
+ Added theme changer back and updated it
= Fixed updates
= Updated quest options
Date 11/14/2020
VT: https://bit.ly/3lwztcn
MD5 Checksum: CC7BF16A3D687C21208E9E986D720CAE
SHA-1 Checksum: CE0C71B4097068E84FA6FC65F4AFE69CBC79AA29
SHA-256 Checksum: D9393C28376DDE1D0582BCF939D1414879EDE6772CE82F83F54C0EA0F239B2F0
SHA-512 Checksum: 326C7A0177E9B8BCFA10CB3B8FAEA025F9C45C599DE5D46CA06DFEE427351F3AE88371C5A0827DEADF7D3F459052C421A145AA5581FE3C4BD2EFAD33BCFFC37B
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+wFCUACgkQvrtJUNxE
TxO0ThAAw6po24zaYQFa+aGrgQNuWYWRxirCkLekEgmy8XVL6Q0rgMeLeq2MrCBP
wi2eBMFlLNOXy1TXOhled89NRBiBeST2Hl4TVv0Qdavd9cSeuGD/rh/PsyxnxY2Y
RWCPeXiYOf0mN1zVylLas+2vk9o/lrNieJir1nMEvyVbUJs8lTDcBdo2vVFwHK9N
nStFPxjqRb8R6smTIsltIh4+juQQMX0GyCcEMUkb5aO6BP34Mpsoaf+9bxV/elJm
UXnFSh5pjzHhkYGKVePtoHev8aFOzLeqIrfyWRJl+7gBMgYIautaxAIE+Zsy3Sai
wxUk9HJeAYwEPhYcIJKGAy+fmeX/TePQjUqLu1Pp+sJ8orstSiMjwXr84UtvyUWZ
+gSTgsQJ1QNUlhp+eJ0D6CchkAwliUXgnpIzwyn1Jj54X3ecHNjMbc5SettlXcBG
qgy5bUx8+v4H4gHmqTyZQNv1bsvIiQlcwPPUtpSzSXrzJPfZjrqPZzUWB8/Vltqc
JIR8FxEqi7+mW6AqrhUjE74N/fFibJTEuv6RALwZIAfMYEuSeFlZlDJYZ9v3H4/X
2jd+wEksbq6uYUl2l3X/7TpMWX29paj18cLD8oTSLK/RvzLXe0hhUcvuHrMxi+14
Q+V7uZYGge4Z5PANGPhd2tSkvw4CyA25OQ868QXjqciSLTfK2SU=
=Yu78
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.16
Changes
+ Speed Limiter for rclone
= Random packagenames more random now
= Bugfixes
Date 11/12/2020
VT: https://bit.ly/2K4Y5Lv
MD5 Checksum: 29978E435BF02865CE61EF6279FB42ED
SHA-1 Checksum: 2E47CFDE7549D088A102F021657E9CD6859EAC47
SHA-256 Checksum: 50057AC0DA315C492C9C45B5801AE99E65B812F5BC18E23622CCAF5FBC48760A
SHA-512 Checksum: E485ADB6088C1F7DC34B65B57A9077E876D3D576D48CCED1FCA691A113CA5F6D0F8A0D31C6C848B6719FF18B7D4C5F829B9DAA8789EA6087F8B1D41005F87A48
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+tHY0ACgkQvrtJUNxE
TxOpjRAAmjaIfvIP+HvfTMGKOEGoVRDIBqEyi8tzq8hn5Z3OadBVLkWT23WblQBw
Ur6BN1fuhH5B8ToGoqX/C1lrgXsvHNDB8frGUWnO1G1KJAQEGwKPRdKyK7YPlrYm
kK74CYuM8w7qjkhX3f50ECZ4Kj1WsE92mIHjfB1xLSGzN0o7Tr1EvFFDnuXrJ0I0
vEbeto0Qo19ORcoP7KFPgGuYmMYJQ2MuwYmWDWAdm4iL1Y9vEKZ4TsHG+KmYPdo8
19YoZj8PsgYxCBy9B+UZfkJnfF7gYKmiAsgnQviDc4BvZccfAVjmWcKkzJueDkvr
GgFmbaFE48svC2NU8Qd2gq6gIX0JrnKACZqopqgorl1817Z7Rsdh2iVwTMOvxbe7
a4kAtDN90KwuRlnwoxeCBdESDSrANbiNi1yaDZc5hr/xOxUsa1JKhk7/8mcdHj78
QoCRoji60Cq8XYeRNDXI32TkZd7ql9c64AjGH1uSySIPXfehOa+m5S53Jo2dRh5p
iI1LGHjTk7EDekIVRh/cPC+hohfUAKYbUcXp15cx0HndW5+galYIH/RAjF0L+Q1U
THz36HpKvLSsgkVkeVjPNJn9Ow6xgyByLTkHrS9D7Kj78FrKiAKr08+aI3+WCpdq
1G9HcH5VzDeZ7/jfVQPhsAn3dPxlTt6ReYzbeFkrO1UHFcTdl58=
=KyH4
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.15HF1
Changes
= Bugfixes
Date 11/06/2020
VT: https://bit.ly/2GDYWRU
MD5 Checksum: F0D51FEC94F8D266390E61E89E6A2EE0
SHA-1 Checksum: 4FB43CFA6021B8360A23858169FAF15468B68EDF
SHA-256 Checksum: CBE414D9A283871099057EE5D8E56AF408996AE9C996C31F92C4DAE16D48B024
SHA-512 Checksum: F16A6B29ECABBB16D25B7F7FC52CB15AE4930B2B17ABAC791BF1F331270F40B047094FDEAF1EF834E72E26AA3A6762AF8BE13EBCB735EB1C1009F884E338D9DE
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+lfEkACgkQvrtJUNxE
TxMDDxAAg+90vrCn0PllPEezzX3AJpy7NFWhFjUlDOLzNFMPa/QdAfF6H5vhEGay
bhX2BDHKSIV86bLkyGPkGHuf3etpXvZsNAmPuDoZpZ4owd1O09DOvAHIJx8F1Eia
Jc9Zovz6lKLAeIbK9ZdChKwTG3hYLIkx3rMgtvnJkZfzUKbhdU9MP0rVEzDPkSfe
ay2CGA9xLBUhPcItUTxhANzrDpRXMGHqbi+Wrscp+KmvnjHzN3Haq2A9rsasXM5Z
RSG8ccLZiI496tJQquTvPXYcnWQQudzcf3yiicztein0xcISEat0FFIVao7TtnS4
cgitvGNtfXXauAxyzjZ7PdgrVuoAE/v4m25pzaTRy7TOfW1uTz2/6lr6tZa38+p9
Bs36KcoK64FcPWjfR7zvvmCUWT/aHlRC9FwMvBHB81WRRk6xGaKl8G2QxfKY/ATl
DNlgYXfXLzipam74XfPHiyK4Sc55WLDQxZfZfD6tqTo4u8qoDESvcEz+pbGe4Wp8
awY4FVeSP1jVQzHgWf+oMTiHm5Gb3qMLUhZ/AHidUWFLhzXmAA4YXxIHKidRjCYT
42Kzs1sjT2A5ll2V7jz4pqoRlsvRAxNZ5KgAZ2R01zo7gS1nGqjyoGq3tLWHbfJk
/kD4QlOwcv06Jvp8aHcPxpccB7KHZGoRT2PB6IQE9Gt72pmAU9c=
=f7yh
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.15
Changes
+ Added a spoofer
+ Added option to auto spoof games with random package name
+ Added new username support for quest 2
= Updated drag and drop sideloading
= Fixed storage label
- Removed troubleshoot form and theme form
Date 11/04/2020
VT: https://bit.ly/3kYCQsb
MD5 Checksum: 39BAB4CEE3D0E387E770BA35F4488C2F
SHA-1 Checksum: C6F311411408BCF5A55034E7A926EA385819F348
SHA-256 Checksum: 64640374EF39DD9CFC4A613A49888E3194994AA934C5E952174A2FCF533E2D19
SHA-512 Checksum: 22769280B732821539100BFA77C67141F271DB401DB3AFB28EF285E352659F9F45A90C8ABE1C0B829770C5AE580CA76A9208505888443C22EE82AAAE7035C6F7
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+jJScACgkQvrtJUNxE
TxMTag//f570tZ4zxL1x1rdajdoYzPD6oaGIabRVPrqVogsFPuVF1Q3AOzr+nzQN
Tiq7yRPmByu/dtBGby2mqL1acQ/9TLYDtmnOAxQJqj4h0KhYlnzdCfqJJbTghtZX
cy44ZqgPW47P608+zC/NfePNt7Fq1rFKN3Bpo/ISoyi5/IVGqGq1Ix/D0SlhiM5X
5VkiY+w5S0rXuAyQ4g6/03AiI9fdNVkREhUh/tYvb7IkxaN9IDlltHByeuvekMjZ
KU+mwZ9habfthB31hp+bAXz82tbIzB4LJ1P8MNadIT8ZXG19zHEY/KlaDp2NjniV
h+V9AnxPHlcZk63yVPOywxpZcv81LflMgs9XItX+zKH7ibniBEu8jxc/2uAjrDF/
JuvnOUKTuH7S2iIzHhKLYZYHiOu8sIuwGC96Ep172PGCAkVVR6CtfNPMmVZRllsY
JG3Pxdrw526SAy3Vqixbbm79Fs1o77resqGM2zl6L7Sr6sH3VnDxabVXxALgo1pH
+LSu5rCLIIsCP1a4MAyy6UgO/+ZLrC1QazR4yY7SRQHAIM48XG4d6CznFCOjczhW
VvYL6gZD7X4xlNBqNMtih8JDHIQ1y7n1f075oCxfWwt02kXhDL/cn8+UZ17IS6EZ
zr/SLm1464/htCZgsUZgQrov6CpHX/xNqAubowkAVOdDREbwh2w=
=QKlt
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.14SU1
Changes
+ Quota errors now will try to redownload the game from another mirror
= Only showing mirror remotes for apps
// Will fix device storage when I get my quest 2 and can debug adb
Date 10/18/2020
VT: https://bit.ly/3kcG62A
MD5 Checksum: 2A30E5F3DB785DC8104A2AA55A83CF53
SHA-1 Checksum: 8376E5971FC4F60995A1125DD9344E52135DB4F7
SHA-256 Checksum: FD5C74067BA00561A540DE5A4F49FA63B99C9520435A51487F997AEC569E9659
SHA-512 Checksum: 6188D6306CA2A3F25DE08E19D1F20046774F7AA30BD745ED24FC7E53126DF3950211B599E3D774F540A6C1DEC177A895FAE70FB564B6AE96F5F10ABDCB9021C1
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+MCbMACgkQvrtJUNxE
TxNMVxAAlIkoTuGTDwXRBFNanulPiYmus9UazHoVFxtG2BELk1/JLPm7dwT29FiZ
oacUhhxLAEfDm169FoPNFCH/6q74xqjACkm8FjwCoas53DekguIvrhJKA3SiBUtZ
m7+hrT3WWGxXoE3+avSFmdBWWvKVA9pNR/DHprHSoinDUvgSfwBHrWD8PtuSIlwU
/jNpzyDnmBfdT4LROq93hcfFXM+POLWs5f3rXFdT+zTZexxlRiG5h7yMmsYdwdov
4jMUSzrBpRXbmmHwDi4KLzsdOJ/5okJgRdPTZm/L1rAoJT0F7QVi2shvkoN7SIH/
Fg+k0ZrNOnlpdAJwLmJD4PkQmxv5zpGSh8w7nbQJ41HgBtTQTh3OCpRRamPzAmfo
A2n/NsYpR8J8u7kGzT1MUnUn2RL+igutSrnQl8R6yR8jFjaTt+F90pBXZ1nnY6mS
8YE9mBBK3365cYVqQzOW1TUSCSzQqwTbfKDHkKrzHQWrpQ8VNMLcJBLZwU8di+4p
u8lt1uT5MRZ+9I80YBXhwzBKkiNYOt5vHpGgt0Ib4WDS7rt/7UnzEAfl8P3VEEfX
6w1HctI2zAVWYutBMv6HL3v23cO+UT8H6Wdgxq36mlMSNiqjLIntfIRrySUOy7JV
D6LE34gzpDGsBIzrpW/Hlz4wGTi6nnY0Ke6DkA1H0UOoDN9ItI4=
=ARa/
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
v1.14
Changes
+ Added the ability to change remotes (mirrors)
+ Rclone errors are now reported properly
= Fixed some bugs
// Will fix device storage when I get my quest 2 and can debug adb
Date 10/17/2020
VT: https://bit.ly/3j8kCm8
MD5 Checksum: B862B807462CE35CC930C2B1118D5692
SHA-1 Checksum: F52C8630C89CAEDB2E90A857E494DE00B137712D
SHA-256 Checksum: 3DDFA2B4CCFC0E9F6F86E8A74E6D3511B9C643F4C4AF19D3878B8704FA360558
SHA-512 Checksum: 16A022D8A4D235D7C537D9F01FE7C5F964A67A3A8CD68B3DC17AF08D94837DAC6CE0C20557D029DC169E5616B36C2A4C36B1647CE0DF930C7694F3FEC3430E70
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl+KrhQACgkQvrtJUNxE
TxP9MRAAjZbYWkbZPK+QMqzNqsgEARs6buzrwc24dth6QEod9Fgmdg5wdinZdG8X
MK467pd9u0JqM3u8DeKSUD0GEzJZStNKsbHfjvNAF3m8toaXLncWy7MYNN9loAra
17MvUBBwB1QgsXtQ3EXT1cBbS3YkQPg5E+ayvY9ZgyiOpDK6fs1tA24NZUWc53kY
TIl5IL3mZNfJck8Xc/QkZJmkBOA89oDToLOjNmZRXXEHNT/eTS6pEkMZonWQjGqF
D2dEfQTOuIAD93JzwcP5wVJFh7z6o65/7tfguDqBsTgoRWODaY+kQJDAxoWN9w/n
nagXg/y30EmE1mWQFUYa1n0V65OzT5+J8VF53DCHkgaejYLfi0lhy8TlWQZpmzen
WJOsP1Oj3ZZ9sErO8waajDBzDZ3kU9NvAOeOblE491w0713MYZYs5BVgoyHi24xO
obcp1gpLi326fkPqajgIFpDHJ014OnaXmoY9ynW9rlZJ4rwJ7WytRDzcpfyk9LV1
G1tlcCS4c/RmuVfZi4Jh0guvOOIpJSqdG4KUtvd548sslTMdHytt+YugbKqcBAto
nWroKcsmg0swAm7YgYmQXqcpM17JC21eUgm3Bc4ZZSDtP4g3Pm7vRO1+hwUNYBE9
QeEMXYDPRsTxdpuEFsbmS/EfnndvJvl9BL92Zt4+T4ruL+II50s=
=r+0B
-----END PGP SIGNATURE-----
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
New version v1.13 Released
Changes
+ Pgp messages will be available now for every update, so you can verify updates easily
= Fixed some bugs like the rclone suicide
- Removed china detection
Date 9/10/2020
MD5 Checksum: 3834485C5AF611523460E639969284F3
SHA-1 Checksum: DAF556D34F80FDE6A6A3D8F338381030B2B19E44
SHA-256 Checksum: 063FABA6A76A98AB862BBBF6F3348F176F66FD4932075E761A5FCAA85785EE4B
SHA-512 Checksum: CC743BD95826664535239BB665934E88A25CC948B95E4A3E8B34379C1E8DEB8FED05EAD87428F4B85D5841ED9101F38E4E3DAFB0EAF3CD2F2E4314B62356104D
You can always get my public key from rookie.wtf/pgp.txt
You can verify the signed message using kleopatra for windows or dark.fail/pgp
-----BEGIN PGP SIGNATURE-----
iQIzBAEBCAAdFiEEG9eYw4mQVDjvGf4lvrtJUNxETxMFAl9aBpMACgkQvrtJUNxE
TxOJcA/+LEzXQtyBhZ0oj22PEk0yMLQYOBLYDB96jf39IqLQAzrIUL339jRcRKMv
yhFWXpvND1wrQl3/LNtFpBSkSnvqUXtxHWg6US+Ov3nnrEvYiwK8D9f1eC5Mt3Wy
4HZIyTh9HcrLsfbnP2kDlLOaMQSIH4rChezF79xZMcx7kRmQ0/hyXlmGAPyWs8t8
5aLxk5YUcfq1Pu+ncqeX+ihYVzQHi2eXaOAIR1rSCEXfHEg9tkRzWcma8tY29gQv
IgGwxF/YnAPOdBtzuakaT88a1MsP+tAcWxmsyvTQHrv1m0h3QPU1DxMFUfAlBjLM
5tHgTTjkXedRpR+Kga5CDuK7L5p1zVMRDINcUOf9MXV2fRurZ+OIHefAd+zbrd0n
vHi1D1sFzb/lT5LCa/vrfO9crRnLdK1EI/5HNeSj9iIdD2jEMbjSjo9yv7LA2MHi
4wnvguRpK5YUGqGc2yyCRxtyKAgXXxLBFNb5K453vdLtDukZIkhLuQVchsk4PutZ
1uIg7/ZmAIPxlEHaLckaV7QEFbq9h2hFWOsSjWAATyvnkp4nxyvAavW4zNQCbd3V
XJhimZkE+3SNAuZGw10nikVz7DFMlI0dyL+jmwIuODcFMZZwkEtBr3J/Ad9V1k+G
DFKYJpBgATHdRTwt7/zZwJCBq0ONheA/6+6VYj8x8Q5rqbiDDdc=
=xp7X
-----END PGP SIGNATURE-----
1.11HF1
= Fixed some crashes that occured when a unauthorized device was used with the sideloader
1.11
+ Added support for multiple devices
1.10SU1
+ Settings should now persist through updates
- Removed download button and hwid stuff
1.10
+ Added back the game size messagebox
+ Added support for unicode in adb
= Fixed restore gamedata
= Clicking the first game won't remove it since it causes problems
= Changed the sideloader icon
1.9SU2
+ Clicking a game on the listbox will now remove it from the list
1.9SU1
- Removed some code I forgot to remove when debugging
1.9
+ Added a queue for downloading games
+ Added a setting for disabling user.json push
1.8SU2
= Install game now won't throw an exception when a game isn't selected
1.8SU1
+ Added debug logs for rclone
1.8
+ Disk info updates every command that changes disk space
= Rclone now logs commands and output
= Changed backup button
1.7.5
+ Made sideloader even faster when opening
+ Added some chiptune music and the setting to stop it
= Fixed donator button broken in 1.7
1.7
+ Removed some freezes
+ Sideloader kills rclone on start and on close if it's open so you dont waste bandwith
+ Updating rclone config now does a hash check first
+ Refresh storage after game install and on game uninstall
1.6
+ Disk space label and check
+ Checks game size before download
= Download and install game button outputs adb log now
- Launch package name button and textbox
1.5
+ Added ETA, based on CURRENT DOWNLOAD SPEED NOT DELTA OF IT
+ Added DLS label instead of showing it in the toolbar
+ Added more indication of what the software is doing, in the toolbar
+ Added some tooltips
1.4
+ Donators can now change the speed of the donate button color change (even disable)
+ Auto update for the rclone config
+ Theme export and import buttons (by gotard)
1.3
+ Added progress bar logic for game downloading with rclone
+ Uninstalling apps now asks the user if it should also remove game data
= Sorted installed apps combobox
= Fixed uninstalling apps by package names lol nobody knew was broken
1.2
+ Added unicode support for rclone
+ Added some delay on game installation
= Fixed stuff
1.1
+ Added Themes
+ Added dollarvr user.json
+ Added user.json transfer on game download
+ Added user.json transfer on first run
= Fixed tab indexes
= Now both drop downs can be visible at the same time
1.0HF1
= Fixed a problem when deleting an app
1.0
+ Added games auto download
+ Added auto troubleshoot
+ Every app installed will have all perms granted
+ Displays apps for games instead of package names if you have rclone set up
+ Uninstall app now will also delete its obb folder
//For auto download you need an rclone config and rclone to be set up correctly
0.15HF1
+ Added list apps button back
= Fixed Uninstall apk and get apk
0.15
= MASSIVE UI REDESIGN
+ Added toggle for tor/clearnet
+ Added download games through tor but still waiting for someone to help me host the files
+ Added download with progress
= Changed adb sideload command to allow downgrades too
- Removed perms stuff, was too buggy
0.14HF1
+ Added donate button
= Fixed ui order
- Removed warning from bulk obb sideload button
0.14
+ Check file hash button
+ Added first run check (will maybe be used to create user.json files)
+ Added drag and drop for apk and obb files
+ Progress bar now works for every adb command
= Moved buttons
- Instructions button
- Removed run custom adb command button and form
0.13
+ Added vrmoo.cn.json
+ Added bulk obb copy
= Message Box now top most
0.12
+ Added settings form
+ Added progress bar (again)
+ Added a new user.json
= Fixed crash on some systems (PerformanceCounter)
= Fixed crash because of file name inconsistency
- Removed performance counters because they made the software not work for some people
0.11
+ Changed normal message boxes to flexible ones
+ Added changelog to update message
= Improved update message
- Removed progressbar
0.10
+ Added few tooltips
+ Sideload folder now works for all apks (recursive search)
= Obb copy and Sideload progress bar problems should be fixed
= Fixed user.json not working if the any of folder had spaces
= Switched back to Message Boxes
0.9
+ Added the buggy progress bar back, uses different "logic"
+ Added an icon (Increased the exe size by like 300% just with that)
+ Added sideload folder button
+ Added Create user.json button and form
+ Changed Message Boxes to notifications
0.8.5
+ Added auto update download
= Fixed a bug where if you didn't have the adb folder it would crash
0.8
+ Every command now shows progress on title bar
+ Automatically run Adb Devices and List Apps on form startup
+ You can now search the App List Combo Box
= Cleaned some code
0.7
= Fixed UI Freezes
+ Added Uninstall APK Button
+ Added Launch package Button
- Removed loading bar
0.6
+ Added List Apk Perms button
+ Added Change Permissions button
+ Added dinamically added checkbox for permisssions
= The software now downloads adb from master instead of v0.3 release
0.5
- Removed Flash Firmware
= Redesigned UI
= Reworked RunAdbCommand function (now it will be possible to do stuff I wasnt able to do before)
= Replaced Ui Buttons, still needs work
+ Added List apk button
+ Added List apk combo box
+ Added get apk function
= Cleaned a bit of code
0.4
+ Added auto download of adb archive
+ Added auto extraction of adb archive
0.3
+ Added new form, you can run custom adb commands now
+ Added recover and backup app data
- Removed Select APK and Select OBB Buttons
- Removed tooltips from removed buttons
+ Sideload APK and Copy Obb buttons now also make you select the file/folder
+ Improved firmware button
0.2
+ Added Flash Firmware button
+ Added few tooltips
+ Renamed buttons
0.1
+ Initial Release
HF - Hot Fix
SU - Small Update

View File

@@ -1,6 +0,0 @@
monterey
hollywood
seacliff
eureka
panther
quest

Binary file not shown.

Binary file not shown.

Binary file not shown.

12
donators.txt Normal file
View File

@@ -0,0 +1,12 @@
CC0E0834BFEBFBFF000906E9;5000;ROOKIE.WTF
184204E0178BFBFF00870F10;0;Flow
E5148390BFEBFBFF000906EA;250;Gotard
5ECC5497178BFBFF00870F10;1024;Saidis21
B0374BE2BFEBFBFF00040651;0;ecirbaf
926C60A8178BFBFF00800F82;250;ThePhantomPickaxe
2A8C5999BFEBFBFF0001067A;0;karl
80ACB80FBFEBFBFF000206C2;4096;JJ-4
9AA172C9BFEBFBFF000906ED;1024;Clayton Bigsby
645C9EADBFEBFBFF000906EA;5000;Heracide
1C51D0CD178BFBFF00870F10;0;Mr.Tibby
287B5C6CBFEBFBFF000906EA;0;videobeer

BIN
icon.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 401 KiB

View File

@@ -1,40 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AdvancedSharpAdbClient" version="3.5.15" targetFramework="net452" />
<package id="Costura.Fody" version="5.7.0" targetFramework="net452" developmentDependency="true" />
<package id="Fody" version="6.8.1" targetFramework="net452" developmentDependency="true" />
<package id="Microsoft.NETCore.Platforms" version="7.0.4" targetFramework="net452" />
<package id="Microsoft.Web.WebView2" version="1.0.2478.35" targetFramework="net452" />
<package id="NETStandard.Library" version="2.0.3" targetFramework="net452" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net452" />
<package id="System.Collections" version="4.3.0" targetFramework="net452" />
<package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net452" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net452" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net452" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net452" />
<package id="System.Globalization" version="4.3.0" targetFramework="net452" />
<package id="System.IO" version="4.3.0" targetFramework="net452" />
<package id="System.IO.Compression" version="4.3.0" targetFramework="net452" />
<package id="System.Linq" version="4.3.0" targetFramework="net452" />
<package id="System.Linq.Expressions" version="4.3.0" targetFramework="net452" />
<package id="System.Net.Http" version="4.3.4" targetFramework="net452" />
<package id="System.Net.Primitives" version="4.3.1" targetFramework="net452" />
<package id="System.ObjectModel" version="4.3.0" targetFramework="net452" />
<package id="System.Reflection" version="4.3.0" targetFramework="net452" />
<package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net452" />
<package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net452" />
<package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net452" />
<package id="System.Runtime" version="4.3.1" targetFramework="net452" />
<package id="System.Runtime.Extensions" version="4.3.1" targetFramework="net452" />
<package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net452" />
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net452" />
<package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net452" />
<package id="System.Text.Encoding" version="4.3.0" targetFramework="net452" />
<package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net452" />
<package id="System.Text.RegularExpressions" version="4.3.1" targetFramework="net452" />
<package id="System.Threading" version="4.3.0" targetFramework="net452" />
<package id="System.Threading.Tasks" version="4.3.0" targetFramework="net452" />
<package id="System.Threading.Timer" version="4.3.0" targetFramework="net452" />
<package id="System.Xml.ReaderWriter" version="4.3.1" targetFramework="net452" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net452" />
<package id="Costura.Fody" version="4.1.0" targetFramework="net452" />
<package id="Fody" version="6.0.0" targetFramework="net452" developmentDependency="true" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net452" />
</packages>

256
spoofer.cs Normal file
View File

@@ -0,0 +1,256 @@
using AndroidSideloader;
using AndroidSideloader.Utilities;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
namespace Spoofer
{
internal class spoofer
{
public static string alias = string.Empty;
public static string password = string.Empty;
public static void Init()
{
if ((File.Exists("keystore.key") == false || File.Exists("details.txt") == false) && HasDependencies())
{
var rand = new Random();
alias = GeneralUtilities.randomString(8);
password = GeneralUtilities.randomString(16);
string subject = $"CN = {GeneralUtilities.randomString(rand.Next(2, 6))}, OU = {GeneralUtilities.randomString(rand.Next(2, 6))}, O = {GeneralUtilities.randomString(rand.Next(2, 6))}, L = {GeneralUtilities.randomString(rand.Next(2, 6))}, ST = {GeneralUtilities.randomString(rand.Next(2, 6))}, C = {GeneralUtilities.randomString(rand.Next(2, 6))}";
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.RedirectStandardError = true;
cmd.StartInfo.WorkingDirectory = Environment.CurrentDirectory;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
cmd.StandardInput.WriteLine($"keytool -genkeypair -alias {alias} -keyalg RSA -keysize 2048 -keystore keystore.key -keypass {password} -storepass {password} -dname \"{subject}\"");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
cmd.WaitForExit();
string keyerror = cmd.StandardError.ReadToEnd();
string keyoutput = cmd.StandardOutput.ReadToEnd();
Logger.Log($"Output: {keyoutput} Error: {keyerror}");
File.WriteAllText("details.txt", $"{alias};{password}");
}
else
{
var temp = File.ReadAllText("details.txt").Split(';');
alias = temp[0];
password = temp[1];
}
}
public static string folderPath = string.Empty;
public static string decompiledPath = string.Empty;
public static string newPackageName = string.Empty;
public static string originalPackageName = string.Empty;
public static string spoofedApkPath = string.Empty;
//public static ProcessOutput ResignAPK(string apkPath)
//{
// string output = "";
// string oldGameName = Path.GetFileName(apkPath);
// folderPath = apkPath.Replace(Path.GetFileName(apkPath), "");
// File.Move(apkPath, $"{folderPath}temp.apk");
// apkPath = $"{folderPath}temp.apk";
// decompiledPath = apkPath.Replace(".apk", "");
// string packagename = PackageName(apkPath);
//}
public static ProcessOutput SpoofApk(string apkPath, string newPackageName, string obbPath = "", string spoofedFileName = "spoofed.apk")
{
//Rename
ProcessOutput output = new ProcessOutput("", "");
string oldGameName = Path.GetFileName(apkPath);
folderPath = apkPath.Replace(Path.GetFileName(apkPath), "");
File.Move(apkPath, $"{folderPath}temp.apk");
apkPath = $"{folderPath}temp.apk";
decompiledPath = apkPath.Replace(".apk", "");
//newPackageName = $"com.{Utilities.randomString(rand.Next(3, 8))}.{Utilities.randomString(rand.Next(3, 8))}";
originalPackageName = PackageName(apkPath);
Logger.Log($"Your app will be spoofed as {newPackageName}");
Logger.Log($"Folderpath: {folderPath} decompiledPaht: {decompiledPath} ");
if (obbPath.Length > 1)
{
RenameObb(obbPath, newPackageName, originalPackageName);
}
Console.WriteLine("Extracting apk...");
output += DecompileApk(apkPath);
Console.WriteLine("Spoofing apk...");
//Rename APK Packagename
string foo = File.ReadAllText($"{decompiledPath}\\AndroidManifest.xml").Replace(originalPackageName, newPackageName);
File.WriteAllText($"{decompiledPath}\\AndroidManifest.xml", foo);
foreach (string file in Directory.EnumerateFiles(decompiledPath, "*.*", SearchOption.AllDirectories))
{
if (Path.GetFileName(file) == "BuildConfig.smali")
{
foo = File.ReadAllText(file).Replace(originalPackageName, newPackageName);
File.WriteAllText(file, foo);
}
}
Console.WriteLine("APK Spoofed");
Console.WriteLine("Rebuilding the APK...");
//spoofedApkPath = $"{Path.GetFileName(apkPath).Replace(".apk", "")}_Spoofed as {newPackageName}.apk";
spoofedApkPath = Path.GetDirectoryName(apkPath) + "\\" + spoofedFileName;
string apkDecompiledPath = Path.GetFileName(apkPath).Replace(".apk", "");
output += GeneralUtilities.startProcess("cmd.exe", folderPath, $"apktool b \"{apkDecompiledPath}\" -o \"{spoofedApkPath}\"");
Logger.Log($"apktool b \"{apkDecompiledPath}\" -o \"{spoofedApkPath}\": {output.Output} {output.Error}");
Console.WriteLine("APK Rebuilt");
//Sign the new apk
Console.WriteLine("Signing the APK...");
if (File.Exists(folderPath + "keystore.key") == false)
File.Copy("keystore.key", $"{folderPath}keystore.key");
output += SignApk(spoofedApkPath);
Console.WriteLine("APK Signed");
//Delete the copy of the key and the decompiled apk folder
Console.WriteLine("Deleting residual files...");
if (string.Equals(folderPath, Environment.CurrentDirectory + "\\") == false)
File.Delete($"{folderPath}keystore.key");
Directory.Delete(decompiledPath, true);
File.Delete(apkPath);
Console.WriteLine("Residual files deleted");
return output;
}
public static ProcessOutput SignApk(string path)
{
//Logger.Log($"jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore keystore.key \"{path}\" {alias}");
Process cmdSign = new Process();
cmdSign.StartInfo.FileName = "cmd.exe";
cmdSign.StartInfo.RedirectStandardInput = true;
cmdSign.StartInfo.WorkingDirectory = folderPath;
cmdSign.StartInfo.CreateNoWindow = true;
cmdSign.StartInfo.UseShellExecute = false;
cmdSign.StartInfo.RedirectStandardOutput = true; //
cmdSign.StartInfo.RedirectStandardError = true; //
cmdSign.Start();
cmdSign.StandardInput.WriteLine($"jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore keystore.key \"{path}\" {alias}");
cmdSign.StandardInput.WriteLine(password);
cmdSign.StandardInput.Flush();
cmdSign.StandardInput.Close();
cmdSign.StandardOutput.Close();
cmdSign.WaitForExit();
//For some reason it hangs when also reading output...
//string output = cmdSign.StandardOutput.ReadToEnd();
//string error = cmdSign.StandardError.ReadToEnd();
//Logger.Log("Jarsign Output " + output);
//Logger.Log("Error: " + error);
//return new ProcessOutput(output, error);
return new ProcessOutput("", "");
}
public static ProcessOutput DecompileApk(string path)
{
ProcessOutput output = GeneralUtilities.startProcess("cmd.exe", folderPath, $"apktool d -f \"{path}\"");
return output;
}
public static bool HasDependencies()
{
if (ExistsOnPath("jarsigner") && ExistsOnPath("apktool") && ExistsOnPath("aapt"))
return true;
return false;
}
public static bool ExistsOnPath(string exeName)
{
try
{
using (Process p = new Process())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "where";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.Arguments = exeName;
p.Start();
p.WaitForExit();
return p.ExitCode==0;
}
}
catch
{
throw new Exception("'where' command is not on path");
}
}
public static string GetFullPath(string exeName)
{
try
{
using (Process p = new Process())
{
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "where";
p.StartInfo.Arguments = exeName;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardOutput = true;
p.Start();
string output = p.StandardOutput.ReadToEnd();
p.WaitForExit();
if (p.ExitCode != 0)
return null;
// just return first match
return output.Substring(0, output.IndexOf(Environment.NewLine));
}
}
catch
{
throw new Exception("'where' command is not on path");
}
}
//Renames obb to new obb according to packagename
public static void RenameObb(string obbPath, string newPackageName, string originalPackageName)
{
Directory.Move(obbPath, obbPath.Replace(originalPackageName, newPackageName));
obbPath = obbPath.Replace(originalPackageName, newPackageName);
foreach (string file in Directory.GetFiles(obbPath))
{
if (Path.GetExtension(file) == ".obb")
{
File.Move(file, file.Replace(originalPackageName, newPackageName));
}
}
}
public static string PackageName(string path)
{
Logger.Log($"aapt dump badging \"{path}\"");
string originalPackageName = GeneralUtilities.startProcess("cmd.exe", path.Replace(Path.GetFileName(path), string.Empty), $"aapt dump badging \"{path}\" | findstr -i \"package: name\"").Output;
Logger.Log($"originalPackageName: {originalPackageName}");
try
{
originalPackageName = originalPackageName.Substring(originalPackageName.IndexOf("package: name='") + 15);
originalPackageName = originalPackageName.Substring(0, originalPackageName.IndexOf("'"));
}
catch
{
return "PackageName ERROR";
}
Console.WriteLine($"Packagename is {originalPackageName}");
return originalPackageName;
}
}
}

View File

@@ -1 +1 @@
3.0.1
1.18.2

View File