Implemented custom ModernListView class, added modern scrollbar to gallery view, reworked list view columns and sorting, added fix to skip 0 MB entries when MR-Fix version exists

Added custom ModernListView class with modern dark theme appearance and refined behavior with smooth text scrolling support. Required a lot of finicking to get the details right. Reworked ListView columns and sorting for size and popularity, including parsing with reformatted GB/MB size and popularity ranking. Updated GalleryView to support new formats and implemented modern scrollbars. Also added logic to skip 0 MB entries when an MR-Fix version of same game exists
This commit is contained in:
jp64k
2025-12-18 05:44:54 +01:00
parent ddb503feec
commit 3148ddcfa3
6 changed files with 1676 additions and 159 deletions

View File

@@ -190,6 +190,7 @@
<Compile Include="GalleryView.cs"> <Compile Include="GalleryView.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="ModernListView.cs" />
<Compile Include="ModernProgessBar.cs"> <Compile Include="ModernProgessBar.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>

View File

@@ -1,4 +1,5 @@
using System.Collections; using System;
using System.Collections;
using System.Windows.Forms; using System.Windows.Forms;
/// <summary> /// <summary>
@@ -41,23 +42,41 @@ public class ListViewColumnSorter : IComparer
ListViewItem listviewX = (ListViewItem)x; ListViewItem listviewX = (ListViewItem)x;
ListViewItem listviewY = (ListViewItem)y; ListViewItem listviewY = (ListViewItem)y;
// Determine if the column requires numeric comparison // Special handling for column 6 (Popularity ranking)
if (SortColumn == 3 || SortColumn == 5) // Numeric columns: VersionCodeIndex, VersionNameIndex if (SortColumn == 6)
{ {
try string textX = listviewX.SubItems[SortColumn].Text;
{ string textY = listviewY.SubItems[SortColumn].Text;
// Parse and compare numeric values directly
int xNum = ParseNumber(listviewX.SubItems[SortColumn].Text);
int yNum = ParseNumber(listviewY.SubItems[SortColumn].Text);
// Compare numerically // Extract numeric values from "#1", "#10", etc.
compareResult = xNum.CompareTo(yNum); // "-" represents unranked and should go to the end
} int rankX = int.MaxValue; // Default for unranked (-)
catch int rankY = int.MaxValue;
if (textX.StartsWith("#") && int.TryParse(textX.Substring(1), out int parsedX))
{ {
// Fallback to string comparison if parsing fails rankX = parsedX;
compareResult = ObjectCompare.Compare(listviewX.SubItems[SortColumn].Text, listviewY.SubItems[SortColumn].Text);
} }
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 else
{ {
@@ -91,6 +110,49 @@ public class ListViewColumnSorter : IComparer
return int.TryParse(text, out int result) ? result : 0; 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;
// 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> /// <summary>
/// Gets or sets the index of the column to be sorted (default is '0'). /// Gets or sets the index of the column to be sorted (default is '0').
/// </summary> /// </summary>

View File

@@ -6,7 +6,9 @@ using System.Drawing;
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms; using System.Windows.Forms;
using static System.Windows.Forms.AxHost;
public enum SortField { Name, LastUpdated, Size, Popularity } public enum SortField { Name, LastUpdated, Size, Popularity }
public enum SortDirection { Ascending, Descending } public enum SortDirection { Ascending, Descending }
@@ -90,6 +92,24 @@ public class FastGalleryPanel : Control
public event EventHandler<int> TileRightClicked; public event EventHandler<int> TileRightClicked;
public event EventHandler<SortField> SortChanged; public event EventHandler<SortField> SortChanged;
[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
private static extern int SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList);
private void ApplyModernScrollbars()
{
if (_scrollBar == null || !_scrollBar.IsHandleCreated) return;
int dark = 1;
int hr = DwmSetWindowAttribute(_scrollBar.Handle, 20, ref dark, sizeof(int));
if (hr != 0)
DwmSetWindowAttribute(_scrollBar.Handle, 19, ref dark, sizeof(int));
if (SetWindowTheme(_scrollBar.Handle, "DarkMode_Explorer", null) != 0)
SetWindowTheme(_scrollBar.Handle, "Explorer", null);
}
private class TileAnimationState private class TileAnimationState
{ {
public float Scale = 1.0f; public float Scale = 1.0f;
@@ -155,6 +175,8 @@ public class FastGalleryPanel : Control
_isScrolling = false; _isScrolling = false;
Invalidate(); Invalidate();
}; };
_scrollBar.HandleCreated += (s, e) => ApplyModernScrollbars();
Controls.Add(_scrollBar); Controls.Add(_scrollBar);
// Animation timer (~120fps) // Animation timer (~120fps)
@@ -353,10 +375,10 @@ public class FastGalleryPanel : Control
case SortField.Popularity: case SortField.Popularity:
if (_currentSortDirection == SortDirection.Ascending) if (_currentSortDirection == SortDirection.Ascending)
_items = _items.OrderBy(i => ParsePopularity(i.SubItems.Count > 6 ? i.SubItems[6].Text : "0")) _items = _items.OrderByDescending(i => ParsePopularity(i.SubItems.Count > 6 ? i.SubItems[6].Text : "-"))
.ThenBy(i => i.Text, new GameNameComparer()).ToList(); .ThenBy(i => i.Text, new GameNameComparer()).ToList();
else else
_items = _items.OrderByDescending(i => ParsePopularity(i.SubItems.Count > 6 ? i.SubItems[6].Text : "0")) _items = _items.OrderBy(i => ParsePopularity(i.SubItems.Count > 6 ? i.SubItems[6].Text : "-"))
.ThenBy(i => i.Text, new GameNameComparer()).ToList(); .ThenBy(i => i.Text, new GameNameComparer()).ToList();
break; break;
} }
@@ -378,12 +400,35 @@ public class FastGalleryPanel : Control
Invalidate(); Invalidate();
} }
private double ParsePopularity(string popStr) private int ParsePopularity(string popStr)
{ {
if (double.TryParse(popStr?.Trim(), System.Globalization.NumberStyles.Any, if (string.IsNullOrEmpty(popStr))
System.Globalization.CultureInfo.InvariantCulture, out double pop)) return int.MaxValue; // Unranked goes to end
return pop;
return 0; popStr = popStr.Trim();
// Handle new format: "#123" or "-"
if (popStr == "-")
{
return int.MaxValue; // Unranked items sort to the end
}
if (popStr.StartsWith("#"))
{
string numPart = popStr.Substring(1);
if (int.TryParse(numPart, out int rank))
{
return rank;
}
}
// Fallback: try parsing as raw number
if (int.TryParse(popStr, out int rawNum))
{
return rawNum;
}
return int.MaxValue; // Unparseable goes to end
} }
// Custom sort to match list sort behaviour: '_' before digits, digits before letters (case-insensitive) // Custom sort to match list sort behaviour: '_' before digits, digits before letters (case-insensitive)
@@ -445,9 +490,39 @@ public class FastGalleryPanel : Control
private double ParseSize(string sizeStr) private double ParseSize(string sizeStr)
{ {
if (double.TryParse(sizeStr?.Trim(), System.Globalization.NumberStyles.Any, if (string.IsNullOrEmpty(sizeStr))
System.Globalization.CultureInfo.InvariantCulture, out double mb)) return 0;
return mb;
// 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; return 0;
} }
@@ -899,7 +974,7 @@ public class FastGalleryPanel : Control
// Size badge (top right) - always visible // Size badge (top right) - always visible
if (item.SubItems.Count > 5) if (item.SubItems.Count > 5)
{ {
string sizeText = FormatSize(item.SubItems[5].Text); string sizeText = item.SubItems[5].Text;
if (!string.IsNullOrEmpty(sizeText)) if (!string.IsNullOrEmpty(sizeText))
{ {
DrawRightAlignedBadge(g, sizeText, x + scaledW - thumbPadding - 4, rightBadgeY, 1.0f); DrawRightAlignedBadge(g, sizeText, x + scaledW - thumbPadding - 4, rightBadgeY, 1.0f);

257
MainForm.Designer.cs generated
View File

@@ -91,6 +91,7 @@ namespace AndroidSideloader
this.speedLabel_Tooltip = new System.Windows.Forms.ToolTip(this.components); this.speedLabel_Tooltip = new System.Windows.Forms.ToolTip(this.components);
this.etaLabel_Tooltip = new System.Windows.Forms.ToolTip(this.components); this.etaLabel_Tooltip = new System.Windows.Forms.ToolTip(this.components);
this.progressDLbtnContainer = new System.Windows.Forms.Panel(); this.progressDLbtnContainer = new System.Windows.Forms.Panel();
this.progressBar = new AndroidSideloader.ModernProgressBar();
this.diskLabel = new System.Windows.Forms.Label(); this.diskLabel = new System.Windows.Forms.Label();
this.questStorageProgressBar = new System.Windows.Forms.Panel(); this.questStorageProgressBar = new System.Windows.Forms.Panel();
this.batteryLevImg = new System.Windows.Forms.PictureBox(); this.batteryLevImg = new System.Windows.Forms.PictureBox();
@@ -119,14 +120,9 @@ namespace AndroidSideloader
this.deviceIdLabel = new System.Windows.Forms.Label(); this.deviceIdLabel = new System.Windows.Forms.Label();
this.rookieStatusLabel = new System.Windows.Forms.Label(); this.rookieStatusLabel = new System.Windows.Forms.Label();
this.sidebarMediaPanel = new System.Windows.Forms.Panel(); this.sidebarMediaPanel = new System.Windows.Forms.Panel();
this.downloadInstallGameButton = new AndroidSideloader.RoundButton();
this.selectedGameLabel = new System.Windows.Forms.Label(); this.selectedGameLabel = new System.Windows.Forms.Label();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.webView21 = new Microsoft.Web.WebView2.WinForms.WebView2();
this.favoriteGame = new System.Windows.Forms.ContextMenuStrip(this.components);
this.favoriteButton = new System.Windows.Forms.ToolStripMenuItem();
this.gamesGalleryView = new System.Windows.Forms.FlowLayoutPanel();
this.btnViewToggle_Tooltip = new System.Windows.Forms.ToolTip(this.components);
this.webViewPlaceholderPanel = new System.Windows.Forms.Panel();
this.searchPanel = new AndroidSideloader.RoundButton(); this.searchPanel = new AndroidSideloader.RoundButton();
this.searchIconPictureBox = new System.Windows.Forms.PictureBox(); this.searchIconPictureBox = new System.Windows.Forms.PictureBox();
this.searchTextBox = new System.Windows.Forms.TextBox(); this.searchTextBox = new System.Windows.Forms.TextBox();
@@ -135,8 +131,12 @@ namespace AndroidSideloader
this.btnInstalled = new AndroidSideloader.RoundButton(); this.btnInstalled = new AndroidSideloader.RoundButton();
this.btnUpdateAvailable = new AndroidSideloader.RoundButton(); this.btnUpdateAvailable = new AndroidSideloader.RoundButton();
this.btnNewerThanList = new AndroidSideloader.RoundButton(); this.btnNewerThanList = new AndroidSideloader.RoundButton();
this.progressBar = new AndroidSideloader.ModernProgressBar(); this.webView21 = new Microsoft.Web.WebView2.WinForms.WebView2();
this.downloadInstallGameButton = new AndroidSideloader.RoundButton(); this.favoriteGame = new System.Windows.Forms.ContextMenuStrip(this.components);
this.favoriteButton = new System.Windows.Forms.ToolStripMenuItem();
this.gamesGalleryView = new System.Windows.Forms.FlowLayoutPanel();
this.btnViewToggle_Tooltip = new System.Windows.Forms.ToolTip(this.components);
this.webViewPlaceholderPanel = new System.Windows.Forms.Panel();
((System.ComponentModel.ISupportInitialize)(this.gamesPictureBox)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.gamesPictureBox)).BeginInit();
this.gamesPictureBox.SuspendLayout(); this.gamesPictureBox.SuspendLayout();
this.progressDLbtnContainer.SuspendLayout(); this.progressDLbtnContainer.SuspendLayout();
@@ -152,10 +152,10 @@ namespace AndroidSideloader
this.statusInfoPanel.SuspendLayout(); this.statusInfoPanel.SuspendLayout();
this.sidebarMediaPanel.SuspendLayout(); this.sidebarMediaPanel.SuspendLayout();
this.tableLayoutPanel1.SuspendLayout(); this.tableLayoutPanel1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.webView21)).BeginInit();
this.favoriteGame.SuspendLayout();
this.searchPanel.SuspendLayout(); this.searchPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.searchIconPictureBox)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.searchIconPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.webView21)).BeginInit();
this.favoriteGame.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
// m_combo // m_combo
@@ -166,7 +166,7 @@ namespace AndroidSideloader
this.m_combo.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor; this.m_combo.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
this.m_combo.Location = new System.Drawing.Point(253, 9); this.m_combo.Location = new System.Drawing.Point(253, 9);
this.m_combo.Name = "m_combo"; this.m_combo.Name = "m_combo";
this.m_combo.Size = new System.Drawing.Size(374, 24); this.m_combo.Size = new System.Drawing.Size(374, 25);
this.m_combo.TabIndex = 0; this.m_combo.TabIndex = 0;
this.m_combo.Text = "Select an Installed App..."; this.m_combo.Text = "Select an Installed App...";
this.m_combo.Visible = false; this.m_combo.Visible = false;
@@ -230,7 +230,7 @@ namespace AndroidSideloader
this.devicesComboBox.Location = new System.Drawing.Point(253, 39); this.devicesComboBox.Location = new System.Drawing.Point(253, 39);
this.devicesComboBox.Margin = new System.Windows.Forms.Padding(2); this.devicesComboBox.Margin = new System.Windows.Forms.Padding(2);
this.devicesComboBox.Name = "devicesComboBox"; this.devicesComboBox.Name = "devicesComboBox";
this.devicesComboBox.Size = new System.Drawing.Size(164, 24); this.devicesComboBox.Size = new System.Drawing.Size(164, 25);
this.devicesComboBox.TabIndex = 1; this.devicesComboBox.TabIndex = 1;
this.devicesComboBox.Text = "Select your device"; this.devicesComboBox.Text = "Select your device";
this.devicesComboBox.Visible = false; this.devicesComboBox.Visible = false;
@@ -246,7 +246,7 @@ namespace AndroidSideloader
this.remotesList.Location = new System.Drawing.Point(567, 40); this.remotesList.Location = new System.Drawing.Point(567, 40);
this.remotesList.Margin = new System.Windows.Forms.Padding(2); this.remotesList.Margin = new System.Windows.Forms.Padding(2);
this.remotesList.Name = "remotesList"; this.remotesList.Name = "remotesList";
this.remotesList.Size = new System.Drawing.Size(67, 24); this.remotesList.Size = new System.Drawing.Size(67, 25);
this.remotesList.TabIndex = 3; this.remotesList.TabIndex = 3;
this.remotesList.Visible = false; this.remotesList.Visible = false;
this.remotesList.SelectedIndexChanged += new System.EventHandler(this.remotesList_SelectedIndexChanged); this.remotesList.SelectedIndexChanged += new System.EventHandler(this.remotesList_SelectedIndexChanged);
@@ -268,10 +268,12 @@ namespace AndroidSideloader
this.DownloadsIndex}); this.DownloadsIndex});
this.gamesListView.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.gamesListView.Font = new System.Drawing.Font("Segoe UI", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.gamesListView.ForeColor = System.Drawing.Color.White; this.gamesListView.ForeColor = System.Drawing.Color.White;
this.gamesListView.FullRowSelect = true;
this.gamesListView.HideSelection = false; this.gamesListView.HideSelection = false;
this.gamesListView.ImeMode = System.Windows.Forms.ImeMode.Off; this.gamesListView.ImeMode = System.Windows.Forms.ImeMode.Off;
this.gamesListView.Location = new System.Drawing.Point(258, 44); this.gamesListView.Location = new System.Drawing.Point(258, 44);
this.gamesListView.Name = "gamesListView"; this.gamesListView.Name = "gamesListView";
this.gamesListView.OwnerDraw = true;
this.gamesListView.ShowGroups = false; this.gamesListView.ShowGroups = false;
this.gamesListView.Size = new System.Drawing.Size(984, 409); this.gamesListView.Size = new System.Drawing.Size(984, 409);
this.gamesListView.TabIndex = 6; this.gamesListView.TabIndex = 6;
@@ -287,7 +289,7 @@ namespace AndroidSideloader
// GameNameIndex // GameNameIndex
// //
this.GameNameIndex.Text = "Game Name"; this.GameNameIndex.Text = "Game Name";
this.GameNameIndex.Width = 158; this.GameNameIndex.Width = 160;
// //
// ReleaseNameIndex // ReleaseNameIndex
// //
@@ -297,29 +299,31 @@ namespace AndroidSideloader
// PackageNameIndex // PackageNameIndex
// //
this.PackageNameIndex.Text = "Package Name"; this.PackageNameIndex.Text = "Package Name";
this.PackageNameIndex.Width = 140; this.PackageNameIndex.Width = 120;
// //
// VersionCodeIndex // VersionCodeIndex
// //
this.VersionCodeIndex.Text = "Version (vs Installed)"; this.VersionCodeIndex.Text = "Version (Rookie/Local)";
this.VersionCodeIndex.Width = 140; this.VersionCodeIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.VersionCodeIndex.Width = 164;
// //
// ReleaseAPKPathIndex // ReleaseAPKPathIndex
// //
this.ReleaseAPKPathIndex.Text = "Last Updated"; this.ReleaseAPKPathIndex.Text = "Last Updated";
this.ReleaseAPKPathIndex.Width = 120; this.ReleaseAPKPathIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.ReleaseAPKPathIndex.Width = 135;
// //
// VersionNameIndex // VersionNameIndex
// //
this.VersionNameIndex.Text = "Size (MB)"; this.VersionNameIndex.Text = "Size";
this.VersionNameIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; this.VersionNameIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.VersionNameIndex.Width = 80; this.VersionNameIndex.Width = 85;
// //
// DownloadsIndex // DownloadsIndex
// //
this.DownloadsIndex.Text = "Popularity"; this.DownloadsIndex.Text = "Popularity";
this.DownloadsIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; this.DownloadsIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
this.DownloadsIndex.Width = 80; this.DownloadsIndex.Width = 100;
// //
// gamesQueueLabel // gamesQueueLabel
// //
@@ -773,6 +777,31 @@ namespace AndroidSideloader
this.progressDLbtnContainer.Size = new System.Drawing.Size(984, 40); this.progressDLbtnContainer.Size = new System.Drawing.Size(984, 40);
this.progressDLbtnContainer.TabIndex = 96; this.progressDLbtnContainer.TabIndex = 96;
// //
// progressBar
//
this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45)))));
this.progressBar.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38)))));
this.progressBar.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.progressBar.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.progressBar.IndeterminateColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.progressBar.IsIndeterminate = false;
this.progressBar.Location = new System.Drawing.Point(1, 23);
this.progressBar.Maximum = 100F;
this.progressBar.Minimum = 0F;
this.progressBar.MinimumSize = new System.Drawing.Size(200, 13);
this.progressBar.Name = "progressBar";
this.progressBar.OperationType = "";
this.progressBar.ProgressEndColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(160)))), ((int)(((byte)(130)))));
this.progressBar.ProgressStartColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(220)))), ((int)(((byte)(190)))));
this.progressBar.Radius = 6;
this.progressBar.Size = new System.Drawing.Size(983, 13);
this.progressBar.StatusText = "";
this.progressBar.TabIndex = 7;
this.progressBar.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(230)))), ((int)(((byte)(230)))));
this.progressBar.Value = 0F;
//
// diskLabel // diskLabel
// //
this.diskLabel.BackColor = System.Drawing.Color.Transparent; this.diskLabel.BackColor = System.Drawing.Color.Transparent;
@@ -1238,6 +1267,35 @@ namespace AndroidSideloader
this.sidebarMediaPanel.Size = new System.Drawing.Size(233, 214); this.sidebarMediaPanel.Size = new System.Drawing.Size(233, 214);
this.sidebarMediaPanel.TabIndex = 101; this.sidebarMediaPanel.TabIndex = 101;
// //
// downloadInstallGameButton
//
this.downloadInstallGameButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(110)))), ((int)(((byte)(215)))), ((int)(((byte)(190)))));
this.downloadInstallGameButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(110)))), ((int)(((byte)(215)))), ((int)(((byte)(190)))));
this.downloadInstallGameButton.BackColor = System.Drawing.Color.Transparent;
this.downloadInstallGameButton.Cursor = System.Windows.Forms.Cursors.Hand;
this.downloadInstallGameButton.DialogResult = System.Windows.Forms.DialogResult.OK;
this.downloadInstallGameButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(16)))), ((int)(((byte)(18)))), ((int)(((byte)(22)))));
this.downloadInstallGameButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(16)))), ((int)(((byte)(18)))), ((int)(((byte)(22)))));
this.downloadInstallGameButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.downloadInstallGameButton.Enabled = false;
this.downloadInstallGameButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.downloadInstallGameButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(59)))), ((int)(((byte)(67)))), ((int)(((byte)(82)))));
this.downloadInstallGameButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.downloadInstallGameButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.downloadInstallGameButton.Location = new System.Drawing.Point(6, 177);
this.downloadInstallGameButton.Margin = new System.Windows.Forms.Padding(0);
this.downloadInstallGameButton.Name = "downloadInstallGameButton";
this.downloadInstallGameButton.Radius = 4;
this.downloadInstallGameButton.Size = new System.Drawing.Size(238, 30);
this.downloadInstallGameButton.Stroke = true;
this.downloadInstallGameButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.downloadInstallGameButton.TabIndex = 94;
this.downloadInstallGameButton.Text = "DOWNLOAD AND INSTALL";
this.downloadInstallGameButton.Transparency = false;
this.downloadInstallGameButton.Click += new System.EventHandler(this.downloadInstallGameButton_Click);
this.downloadInstallGameButton.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form1_DragDrop);
this.downloadInstallGameButton.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form1_DragEnter);
//
// selectedGameLabel // selectedGameLabel
// //
this.selectedGameLabel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29))))); this.selectedGameLabel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(20)))), ((int)(((byte)(24)))), ((int)(((byte)(29)))));
@@ -1276,58 +1334,6 @@ namespace AndroidSideloader
this.tableLayoutPanel1.Size = new System.Drawing.Size(984, 34); this.tableLayoutPanel1.Size = new System.Drawing.Size(984, 34);
this.tableLayoutPanel1.TabIndex = 97; this.tableLayoutPanel1.TabIndex = 97;
// //
// webView21
//
this.webView21.AllowExternalDrop = true;
this.webView21.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.webView21.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(26)))), ((int)(((byte)(30)))));
this.webView21.CreationProperties = null;
this.webView21.DefaultBackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(26)))), ((int)(((byte)(30)))));
this.webView21.Location = new System.Drawing.Point(259, 496);
this.webView21.Name = "webView21";
this.webView21.Size = new System.Drawing.Size(384, 216);
this.webView21.TabIndex = 98;
this.webView21.ZoomFactor = 1D;
//
// favoriteGame
//
this.favoriteGame.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(42)))), ((int)(((byte)(48)))));
this.favoriteGame.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.favoriteButton});
this.favoriteGame.Name = "favoriteGame";
this.favoriteGame.ShowImageMargin = false;
this.favoriteGame.Size = new System.Drawing.Size(149, 26);
//
// favoriteButton
//
this.favoriteButton.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(42)))), ((int)(((byte)(48)))));
this.favoriteButton.ForeColor = System.Drawing.Color.White;
this.favoriteButton.Name = "favoriteButton";
this.favoriteButton.Size = new System.Drawing.Size(148, 22);
this.favoriteButton.Text = "★ Add to Favorites";
this.favoriteButton.Click += new System.EventHandler(this.favoriteButton_Click);
//
// gamesGalleryView
//
this.gamesGalleryView.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.gamesGalleryView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(15)))), ((int)(((byte)(15)))), ((int)(((byte)(15)))));
this.gamesGalleryView.Location = new System.Drawing.Point(258, 44);
this.gamesGalleryView.Name = "gamesGalleryView";
this.gamesGalleryView.Size = new System.Drawing.Size(984, 409);
this.gamesGalleryView.TabIndex = 102;
//
// webViewPlaceholderPanel
//
this.webViewPlaceholderPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.webViewPlaceholderPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(26)))), ((int)(((byte)(30)))));
this.webViewPlaceholderPanel.Location = new System.Drawing.Point(259, 496);
this.webViewPlaceholderPanel.Name = "webViewPlaceholderPanel";
this.webViewPlaceholderPanel.Size = new System.Drawing.Size(384, 217);
this.webViewPlaceholderPanel.TabIndex = 103;
this.webViewPlaceholderPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.webViewPlaceholderPanel_Paint);
//
// searchPanel // searchPanel
// //
this.searchPanel.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(56)))), ((int)(((byte)(70))))); this.searchPanel.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(51)))), ((int)(((byte)(56)))), ((int)(((byte)(70)))));
@@ -1511,59 +1517,57 @@ namespace AndroidSideloader
this.btnNewerThanList.Transparency = false; this.btnNewerThanList.Transparency = false;
this.btnNewerThanList.Click += new System.EventHandler(this.btnNewerThanList_Click); this.btnNewerThanList.Click += new System.EventHandler(this.btnNewerThanList_Click);
// //
// progressBar // webView21
// //
this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) this.webView21.AllowExternalDrop = true;
this.webView21.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.webView21.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(26)))), ((int)(((byte)(30)))));
this.webView21.CreationProperties = null;
this.webView21.DefaultBackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(26)))), ((int)(((byte)(30)))));
this.webView21.Location = new System.Drawing.Point(259, 496);
this.webView21.Name = "webView21";
this.webView21.Size = new System.Drawing.Size(384, 216);
this.webView21.TabIndex = 98;
this.webView21.ZoomFactor = 1D;
//
// favoriteGame
//
this.favoriteGame.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(42)))), ((int)(((byte)(48)))));
this.favoriteGame.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.favoriteButton});
this.favoriteGame.Name = "favoriteGame";
this.favoriteGame.ShowImageMargin = false;
this.favoriteGame.Size = new System.Drawing.Size(149, 26);
//
// favoriteButton
//
this.favoriteButton.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(42)))), ((int)(((byte)(48)))));
this.favoriteButton.ForeColor = System.Drawing.Color.White;
this.favoriteButton.Name = "favoriteButton";
this.favoriteButton.Size = new System.Drawing.Size(148, 22);
this.favoriteButton.Text = "★ Add to Favorites";
this.favoriteButton.Click += new System.EventHandler(this.favoriteButton_Click);
//
// gamesGalleryView
//
this.gamesGalleryView.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))); | System.Windows.Forms.AnchorStyles.Right)));
this.progressBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(35)))), ((int)(((byte)(45))))); this.gamesGalleryView.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(15)))), ((int)(((byte)(15)))), ((int)(((byte)(15)))));
this.progressBar.BackgroundColor = System.Drawing.Color.FromArgb(((int)(((byte)(28)))), ((int)(((byte)(32)))), ((int)(((byte)(38))))); this.gamesGalleryView.Location = new System.Drawing.Point(258, 44);
this.progressBar.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold); this.gamesGalleryView.Name = "gamesGalleryView";
this.progressBar.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173))))); this.gamesGalleryView.Size = new System.Drawing.Size(984, 409);
this.progressBar.IndeterminateColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173))))); this.gamesGalleryView.TabIndex = 102;
this.progressBar.IsIndeterminate = false;
this.progressBar.Location = new System.Drawing.Point(1, 23);
this.progressBar.Maximum = 100F;
this.progressBar.Minimum = 0F;
this.progressBar.MinimumSize = new System.Drawing.Size(200, 13);
this.progressBar.Name = "progressBar";
this.progressBar.OperationType = "";
this.progressBar.ProgressEndColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(160)))), ((int)(((byte)(130)))));
this.progressBar.ProgressStartColor = System.Drawing.Color.FromArgb(((int)(((byte)(120)))), ((int)(((byte)(220)))), ((int)(((byte)(190)))));
this.progressBar.Radius = 6;
this.progressBar.Size = new System.Drawing.Size(983, 13);
this.progressBar.StatusText = "";
this.progressBar.TabIndex = 7;
this.progressBar.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(230)))), ((int)(((byte)(230)))), ((int)(((byte)(230)))));
this.progressBar.Value = 0F;
// //
// downloadInstallGameButton // webViewPlaceholderPanel
// //
this.downloadInstallGameButton.Active1 = System.Drawing.Color.FromArgb(((int)(((byte)(110)))), ((int)(((byte)(215)))), ((int)(((byte)(190))))); this.webViewPlaceholderPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.downloadInstallGameButton.Active2 = System.Drawing.Color.FromArgb(((int)(((byte)(110)))), ((int)(((byte)(215)))), ((int)(((byte)(190))))); this.webViewPlaceholderPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(24)))), ((int)(((byte)(26)))), ((int)(((byte)(30)))));
this.downloadInstallGameButton.BackColor = System.Drawing.Color.Transparent; this.webViewPlaceholderPanel.Location = new System.Drawing.Point(259, 496);
this.downloadInstallGameButton.Cursor = System.Windows.Forms.Cursors.Hand; this.webViewPlaceholderPanel.Name = "webViewPlaceholderPanel";
this.downloadInstallGameButton.DialogResult = System.Windows.Forms.DialogResult.OK; this.webViewPlaceholderPanel.Size = new System.Drawing.Size(384, 217);
this.downloadInstallGameButton.Disabled1 = System.Drawing.Color.FromArgb(((int)(((byte)(16)))), ((int)(((byte)(18)))), ((int)(((byte)(22))))); this.webViewPlaceholderPanel.TabIndex = 103;
this.downloadInstallGameButton.Disabled2 = System.Drawing.Color.FromArgb(((int)(((byte)(16)))), ((int)(((byte)(18)))), ((int)(((byte)(22))))); this.webViewPlaceholderPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.webViewPlaceholderPanel_Paint);
this.downloadInstallGameButton.DisabledStrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(55)))), ((int)(((byte)(65)))));
this.downloadInstallGameButton.Enabled = false;
this.downloadInstallGameButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Bold);
this.downloadInstallGameButton.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(59)))), ((int)(((byte)(67)))), ((int)(((byte)(82)))));
this.downloadInstallGameButton.Inactive1 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.downloadInstallGameButton.Inactive2 = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.downloadInstallGameButton.Location = new System.Drawing.Point(6, 177);
this.downloadInstallGameButton.Margin = new System.Windows.Forms.Padding(0);
this.downloadInstallGameButton.Name = "downloadInstallGameButton";
this.downloadInstallGameButton.Radius = 4;
this.downloadInstallGameButton.Size = new System.Drawing.Size(238, 30);
this.downloadInstallGameButton.Stroke = true;
this.downloadInstallGameButton.StrokeColor = System.Drawing.Color.FromArgb(((int)(((byte)(93)))), ((int)(((byte)(203)))), ((int)(((byte)(173)))));
this.downloadInstallGameButton.TabIndex = 94;
this.downloadInstallGameButton.Text = "DOWNLOAD AND INSTALL";
this.downloadInstallGameButton.Transparency = false;
this.downloadInstallGameButton.Click += new System.EventHandler(this.downloadInstallGameButton_Click);
this.downloadInstallGameButton.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form1_DragDrop);
this.downloadInstallGameButton.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form1_DragEnter);
// //
// MainForm // MainForm
// //
@@ -1615,11 +1619,11 @@ namespace AndroidSideloader
this.statusInfoPanel.ResumeLayout(false); this.statusInfoPanel.ResumeLayout(false);
this.sidebarMediaPanel.ResumeLayout(false); this.sidebarMediaPanel.ResumeLayout(false);
this.tableLayoutPanel1.ResumeLayout(false); this.tableLayoutPanel1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.webView21)).EndInit();
this.favoriteGame.ResumeLayout(false);
this.searchPanel.ResumeLayout(false); this.searchPanel.ResumeLayout(false);
this.searchPanel.PerformLayout(); this.searchPanel.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.searchIconPictureBox)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.searchIconPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.webView21)).EndInit();
this.favoriteGame.ResumeLayout(false);
this.ResumeLayout(false); this.ResumeLayout(false);
this.PerformLayout(); this.PerformLayout();
@@ -1732,5 +1736,6 @@ namespace AndroidSideloader
private Label activeMirrorLabel; private Label activeMirrorLabel;
private Label sideloadingStatusLabel; private Label sideloadingStatusLabel;
private Label rookieStatusLabel; private Label rookieStatusLabel;
private ModernListView _listViewRenderer;
} }
} }

View File

@@ -127,9 +127,18 @@ namespace AndroidSideloader
gamesQueListBox.DataSource = gamesQueueList; gamesQueListBox.DataSource = gamesQueueList;
SetCurrentLogPath(); SetCurrentLogPath();
StartTimers(); StartTimers();
lvwColumnSorter = new ListViewColumnSorter(); lvwColumnSorter = new ListViewColumnSorter();
gamesListView.ListViewItemSorter = lvwColumnSorter; gamesListView.ListViewItemSorter = lvwColumnSorter;
// Initialize modern ListView renderer
_listViewRenderer = new ModernListView(gamesListView, lvwColumnSorter);
// Set a larger item height for increased spacing between rows
ImageList rowSpacingImageList = new ImageList();
rowSpacingImageList.ImageSize = new Size(1, 28);
gamesListView.SmallImageList = rowSpacingImageList;
SubscribeToHoverEvents(questInfoPanel); SubscribeToHoverEvents(questInfoPanel);
this.Resize += MainForm_Resize; this.Resize += MainForm_Resize;
@@ -2163,6 +2172,63 @@ namespace AndroidSideloader
Logger.Log($"Cloud versions precomputed in {sw.ElapsedMilliseconds}ms"); Logger.Log($"Cloud versions precomputed in {sw.ElapsedMilliseconds}ms");
sw.Restart(); sw.Restart();
// Calculate popularity rankings
var popularityScores = new Dictionary<string, double>(StringComparer.OrdinalIgnoreCase);
foreach (string[] release in SideloaderRCLONE.games)
{
string packagename = release[SideloaderRCLONE.PackageNameIndex];
// Parse popularity score from column 6
if (release.Length > 6 && double.TryParse(release[6], out double score))
{
// Track the highest score per package
if (popularityScores.TryGetValue(packagename, out var existing))
{
if (score > existing)
popularityScores[packagename] = score;
}
else
{
popularityScores[packagename] = score;
}
}
}
// Sort packages by popularity (descending) and assign rankings
var rankedPackages = popularityScores
.Where(kvp => kvp.Value > 0) // Exclude 0.00 scores
.OrderByDescending(kvp => kvp.Value)
.Select((kvp, index) => new { Package = kvp.Key, Rank = index + 1 })
.ToDictionary(x => x.Package, x => x.Rank, StringComparer.OrdinalIgnoreCase);
Logger.Log($"Popularity rankings calculated for {rankedPackages.Count} games in {sw.ElapsedMilliseconds}ms");
sw.Restart();
// Build MR-Fix lookup. map base game name to whether an MR-Fix exists
var mrFixGames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (string[] release in SideloaderRCLONE.games)
{
string gameName = release[SideloaderRCLONE.GameNameIndex];
// Check if game name contains "(MR-Fix)" using IndexOf for case-insensitive search
if (gameName.IndexOf("(MR-Fix)", StringComparison.OrdinalIgnoreCase) >= 0)
{
// Extract base game name by removing "(MR-Fix)" suffix
int mrFixIndex = gameName.IndexOf("(MR-Fix)", StringComparison.OrdinalIgnoreCase);
string baseGameName = gameName.Substring(0, mrFixIndex).Trim();
if (gameName.Length > mrFixIndex + 8)
{
baseGameName += gameName.Substring(mrFixIndex + 8);
}
baseGameName = baseGameName.Trim();
mrFixGames.Add(baseGameName);
}
}
Logger.Log($"MR-Fix lookup built with {mrFixGames.Count} games in {sw.ElapsedMilliseconds}ms");
sw.Restart();
// Process games on background thread // Process games on background thread
await Task.Run(() => await Task.Run(() =>
{ {
@@ -2179,7 +2245,28 @@ namespace AndroidSideloader
var item = new ListViewItem(release); var item = new ListViewItem(release);
// Add installed version as additional column // Check if this is a 0 MB entry that should be excluded
bool shouldSkip = false;
if (release.Length > 5 && double.TryParse(release[5], out double sizeInMB))
{
// If size is 0 MB and this is not already an MR-Fix version
if (sizeInMB == 0 && gameName.IndexOf("(MR-Fix)", StringComparison.OrdinalIgnoreCase) < 0)
{
// Check if there's an MR-Fix version of this game
if (mrFixGames.Contains(gameName))
{
shouldSkip = true;
//Logger.Log($"Skipping 0 MB entry for '{gameName}' - MR-Fix version exists");
}
}
}
if (shouldSkip)
{
continue; // Skip this entry
}
// Show the installed version
ulong installedVersion = 0; ulong installedVersion = 0;
if (installedVersions.TryGetValue(packagename, out ulong installedVersionInt)) if (installedVersions.TryGetValue(packagename, out ulong installedVersionInt))
@@ -2231,10 +2318,43 @@ namespace AndroidSideloader
} }
} }
// Add the installed version to the ListView item
if (installedVersion != 0) if (installedVersion != 0)
{ {
item.SubItems[3].Text = $"{item.SubItems[3].Text} ({installedVersion})"; // Show the installed version and attach 'v' to both versions
item.SubItems[3].Text = $"v{item.SubItems[3].Text} / v{installedVersion}";
}
else
{
// Attach 'v' to remote version
item.SubItems[3].Text = $"v{item.SubItems[3].Text}";
}
// Remove ' UTC' from last updated
item.SubItems[4].Text = item.SubItems[4].Text.Replace(" UTC", "");
// Convert size to GB or MB
if (double.TryParse(item.SubItems[5].Text, out double itemSizeInMB))
{
if (itemSizeInMB >= 1024)
{
double sizeInGB = itemSizeInMB / 1024;
item.SubItems[5].Text = $"{sizeInGB:F2} GB";
}
else
{
item.SubItems[5].Text = $"{itemSizeInMB:F0} MB";
}
}
// STEP 4: Replace popularity score with ranking
if (rankedPackages.TryGetValue(packagename, out int rank))
{
item.SubItems[6].Text = $"#{rank}";
}
else
{
// Unranked (0.00 popularity or not found)
item.SubItems[6].Text = "-";
} }
if (favoriteView) if (favoriteView)
@@ -4382,19 +4502,34 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
private void listView1_ColumnClick(object sender, ColumnClickEventArgs e) private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
{ {
// Determine if clicked column is already the column that is being sorted. // Determine sort order
if (e.Column == lvwColumnSorter.SortColumn) if (e.Column == lvwColumnSorter.SortColumn)
{ {
// Reverse the current sort direction for this column.
lvwColumnSorter.Order = lvwColumnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; lvwColumnSorter.Order = lvwColumnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
} }
else else
{ {
lvwColumnSorter.SortColumn = e.Column; lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = e.Column == 4 ? SortOrder.Descending : SortOrder.Ascending; lvwColumnSorter.Order =
(e.Column == 4 || e.Column == 5) ? SortOrder.Descending :
(e.Column == 6) ? SortOrder.Ascending :
SortOrder.Ascending;
} }
// Perform the sort with these new sort options.
gamesListView.Sort(); // Suspend drawing during sort
gamesListView.BeginUpdate();
try
{
gamesListView.Sort();
}
finally
{
gamesListView.EndUpdate();
}
// Invalidate header to update sort indicators
gamesListView.Invalidate(new Rectangle(0, 0, gamesListView.ClientSize.Width,
gamesListView.Font.Height + 8));
} }
private void CheckEnter(object sender, System.Windows.Forms.KeyPressEventArgs e) private void CheckEnter(object sender, System.Windows.Forms.KeyPressEventArgs e)
@@ -7253,5 +7388,12 @@ function onYouTubeIframeAPIReady() {
action.Invoke(); action.Invoke();
} }
} }
public static void SetStyle(this Control control, ControlStyles styles, bool value)
{
typeof(Control).GetMethod("SetStyle",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
?.Invoke(control, new object[] { styles, value });
}
} }
} }

1232
ModernListView.cs Normal file

File diff suppressed because it is too large Load Diff