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:
@@ -190,6 +190,7 @@
|
||||
<Compile Include="GalleryView.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="ModernListView.cs" />
|
||||
<Compile Include="ModernProgessBar.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Windows.Forms;
|
||||
|
||||
/// <summary>
|
||||
@@ -41,23 +42,41 @@ public class ListViewColumnSorter : IComparer
|
||||
ListViewItem listviewX = (ListViewItem)x;
|
||||
ListViewItem listviewY = (ListViewItem)y;
|
||||
|
||||
// Determine if the column requires numeric comparison
|
||||
if (SortColumn == 3 || SortColumn == 5) // Numeric columns: VersionCodeIndex, VersionNameIndex
|
||||
// Special handling for column 6 (Popularity ranking)
|
||||
if (SortColumn == 6)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse and compare numeric values directly
|
||||
int xNum = ParseNumber(listviewX.SubItems[SortColumn].Text);
|
||||
int yNum = ParseNumber(listviewY.SubItems[SortColumn].Text);
|
||||
string textX = listviewX.SubItems[SortColumn].Text;
|
||||
string textY = listviewY.SubItems[SortColumn].Text;
|
||||
|
||||
// Compare numerically
|
||||
compareResult = xNum.CompareTo(yNum);
|
||||
}
|
||||
catch
|
||||
// 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))
|
||||
{
|
||||
// Fallback to string comparison if parsing fails
|
||||
compareResult = ObjectCompare.Compare(listviewX.SubItems[SortColumn].Text, listviewY.SubItems[SortColumn].Text);
|
||||
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
|
||||
{
|
||||
@@ -91,6 +110,49 @@ public class ListViewColumnSorter : IComparer
|
||||
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>
|
||||
/// Gets or sets the index of the column to be sorted (default is '0').
|
||||
/// </summary>
|
||||
|
||||
@@ -6,7 +6,9 @@ using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
using static System.Windows.Forms.AxHost;
|
||||
|
||||
public enum SortField { Name, LastUpdated, Size, Popularity }
|
||||
public enum SortDirection { Ascending, Descending }
|
||||
@@ -90,6 +92,24 @@ public class FastGalleryPanel : Control
|
||||
public event EventHandler<int> TileRightClicked;
|
||||
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
|
||||
{
|
||||
public float Scale = 1.0f;
|
||||
@@ -155,6 +175,8 @@ public class FastGalleryPanel : Control
|
||||
_isScrolling = false;
|
||||
Invalidate();
|
||||
};
|
||||
|
||||
_scrollBar.HandleCreated += (s, e) => ApplyModernScrollbars();
|
||||
Controls.Add(_scrollBar);
|
||||
|
||||
// Animation timer (~120fps)
|
||||
@@ -353,10 +375,10 @@ public class FastGalleryPanel : Control
|
||||
|
||||
case SortField.Popularity:
|
||||
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();
|
||||
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();
|
||||
break;
|
||||
}
|
||||
@@ -378,12 +400,35 @@ public class FastGalleryPanel : Control
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
private double ParsePopularity(string popStr)
|
||||
private int ParsePopularity(string popStr)
|
||||
{
|
||||
if (double.TryParse(popStr?.Trim(), System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out double pop))
|
||||
return pop;
|
||||
return 0;
|
||||
if (string.IsNullOrEmpty(popStr))
|
||||
return int.MaxValue; // Unranked goes to end
|
||||
|
||||
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)
|
||||
@@ -445,9 +490,39 @@ public class FastGalleryPanel : Control
|
||||
|
||||
private double ParseSize(string sizeStr)
|
||||
{
|
||||
if (double.TryParse(sizeStr?.Trim(), System.Globalization.NumberStyles.Any,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -899,7 +974,7 @@ public class FastGalleryPanel : Control
|
||||
// Size badge (top right) - always visible
|
||||
if (item.SubItems.Count > 5)
|
||||
{
|
||||
string sizeText = FormatSize(item.SubItems[5].Text);
|
||||
string sizeText = item.SubItems[5].Text;
|
||||
if (!string.IsNullOrEmpty(sizeText))
|
||||
{
|
||||
DrawRightAlignedBadge(g, sizeText, x + scaledW - thumbPadding - 4, rightBadgeY, 1.0f);
|
||||
|
||||
257
MainForm.Designer.cs
generated
257
MainForm.Designer.cs
generated
@@ -91,6 +91,7 @@ namespace AndroidSideloader
|
||||
this.speedLabel_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.progressBar = new AndroidSideloader.ModernProgressBar();
|
||||
this.diskLabel = new System.Windows.Forms.Label();
|
||||
this.questStorageProgressBar = new System.Windows.Forms.Panel();
|
||||
this.batteryLevImg = new System.Windows.Forms.PictureBox();
|
||||
@@ -119,14 +120,9 @@ namespace AndroidSideloader
|
||||
this.deviceIdLabel = new System.Windows.Forms.Label();
|
||||
this.rookieStatusLabel = new System.Windows.Forms.Label();
|
||||
this.sidebarMediaPanel = new System.Windows.Forms.Panel();
|
||||
this.downloadInstallGameButton = new AndroidSideloader.RoundButton();
|
||||
this.selectedGameLabel = new System.Windows.Forms.Label();
|
||||
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.searchIconPictureBox = new System.Windows.Forms.PictureBox();
|
||||
this.searchTextBox = new System.Windows.Forms.TextBox();
|
||||
@@ -135,8 +131,12 @@ namespace AndroidSideloader
|
||||
this.btnInstalled = new AndroidSideloader.RoundButton();
|
||||
this.btnUpdateAvailable = new AndroidSideloader.RoundButton();
|
||||
this.btnNewerThanList = new AndroidSideloader.RoundButton();
|
||||
this.progressBar = new AndroidSideloader.ModernProgressBar();
|
||||
this.downloadInstallGameButton = new AndroidSideloader.RoundButton();
|
||||
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();
|
||||
((System.ComponentModel.ISupportInitialize)(this.gamesPictureBox)).BeginInit();
|
||||
this.gamesPictureBox.SuspendLayout();
|
||||
this.progressDLbtnContainer.SuspendLayout();
|
||||
@@ -152,10 +152,10 @@ namespace AndroidSideloader
|
||||
this.statusInfoPanel.SuspendLayout();
|
||||
this.sidebarMediaPanel.SuspendLayout();
|
||||
this.tableLayoutPanel1.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.webView21)).BeginInit();
|
||||
this.favoriteGame.SuspendLayout();
|
||||
this.searchPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.searchIconPictureBox)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.webView21)).BeginInit();
|
||||
this.favoriteGame.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// m_combo
|
||||
@@ -166,7 +166,7 @@ namespace AndroidSideloader
|
||||
this.m_combo.ForeColor = global::AndroidSideloader.Properties.Settings.Default.FontColor;
|
||||
this.m_combo.Location = new System.Drawing.Point(253, 9);
|
||||
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.Text = "Select an Installed App...";
|
||||
this.m_combo.Visible = false;
|
||||
@@ -230,7 +230,7 @@ namespace AndroidSideloader
|
||||
this.devicesComboBox.Location = new System.Drawing.Point(253, 39);
|
||||
this.devicesComboBox.Margin = new System.Windows.Forms.Padding(2);
|
||||
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.Text = "Select your device";
|
||||
this.devicesComboBox.Visible = false;
|
||||
@@ -246,7 +246,7 @@ namespace AndroidSideloader
|
||||
this.remotesList.Location = new System.Drawing.Point(567, 40);
|
||||
this.remotesList.Margin = new System.Windows.Forms.Padding(2);
|
||||
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.Visible = false;
|
||||
this.remotesList.SelectedIndexChanged += new System.EventHandler(this.remotesList_SelectedIndexChanged);
|
||||
@@ -268,10 +268,12 @@ namespace AndroidSideloader
|
||||
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.ForeColor = System.Drawing.Color.White;
|
||||
this.gamesListView.FullRowSelect = true;
|
||||
this.gamesListView.HideSelection = false;
|
||||
this.gamesListView.ImeMode = System.Windows.Forms.ImeMode.Off;
|
||||
this.gamesListView.Location = new System.Drawing.Point(258, 44);
|
||||
this.gamesListView.Name = "gamesListView";
|
||||
this.gamesListView.OwnerDraw = true;
|
||||
this.gamesListView.ShowGroups = false;
|
||||
this.gamesListView.Size = new System.Drawing.Size(984, 409);
|
||||
this.gamesListView.TabIndex = 6;
|
||||
@@ -287,7 +289,7 @@ namespace AndroidSideloader
|
||||
// GameNameIndex
|
||||
//
|
||||
this.GameNameIndex.Text = "Game Name";
|
||||
this.GameNameIndex.Width = 158;
|
||||
this.GameNameIndex.Width = 160;
|
||||
//
|
||||
// ReleaseNameIndex
|
||||
//
|
||||
@@ -297,29 +299,31 @@ namespace AndroidSideloader
|
||||
// PackageNameIndex
|
||||
//
|
||||
this.PackageNameIndex.Text = "Package Name";
|
||||
this.PackageNameIndex.Width = 140;
|
||||
this.PackageNameIndex.Width = 120;
|
||||
//
|
||||
// VersionCodeIndex
|
||||
//
|
||||
this.VersionCodeIndex.Text = "Version (vs Installed)";
|
||||
this.VersionCodeIndex.Width = 140;
|
||||
this.VersionCodeIndex.Text = "Version (Rookie/Local)";
|
||||
this.VersionCodeIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.VersionCodeIndex.Width = 164;
|
||||
//
|
||||
// ReleaseAPKPathIndex
|
||||
//
|
||||
this.ReleaseAPKPathIndex.Text = "Last Updated";
|
||||
this.ReleaseAPKPathIndex.Width = 120;
|
||||
this.ReleaseAPKPathIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.ReleaseAPKPathIndex.Width = 135;
|
||||
//
|
||||
// VersionNameIndex
|
||||
//
|
||||
this.VersionNameIndex.Text = "Size (MB)";
|
||||
this.VersionNameIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
this.VersionNameIndex.Width = 80;
|
||||
this.VersionNameIndex.Text = "Size";
|
||||
this.VersionNameIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.VersionNameIndex.Width = 85;
|
||||
//
|
||||
// DownloadsIndex
|
||||
//
|
||||
this.DownloadsIndex.Text = "Popularity";
|
||||
this.DownloadsIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
|
||||
this.DownloadsIndex.Width = 80;
|
||||
this.DownloadsIndex.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
|
||||
this.DownloadsIndex.Width = 100;
|
||||
//
|
||||
// gamesQueueLabel
|
||||
//
|
||||
@@ -773,6 +777,31 @@ namespace AndroidSideloader
|
||||
this.progressDLbtnContainer.Size = new System.Drawing.Size(984, 40);
|
||||
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
|
||||
//
|
||||
this.diskLabel.BackColor = System.Drawing.Color.Transparent;
|
||||
@@ -1238,6 +1267,35 @@ namespace AndroidSideloader
|
||||
this.sidebarMediaPanel.Size = new System.Drawing.Size(233, 214);
|
||||
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
|
||||
//
|
||||
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.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
|
||||
//
|
||||
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.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)));
|
||||
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;
|
||||
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;
|
||||
//
|
||||
// downloadInstallGameButton
|
||||
// webViewPlaceholderPanel
|
||||
//
|
||||
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);
|
||||
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);
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
@@ -1615,11 +1619,11 @@ namespace AndroidSideloader
|
||||
this.statusInfoPanel.ResumeLayout(false);
|
||||
this.sidebarMediaPanel.ResumeLayout(false);
|
||||
this.tableLayoutPanel1.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.webView21)).EndInit();
|
||||
this.favoriteGame.ResumeLayout(false);
|
||||
this.searchPanel.ResumeLayout(false);
|
||||
this.searchPanel.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.searchIconPictureBox)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.webView21)).EndInit();
|
||||
this.favoriteGame.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@@ -1732,5 +1736,6 @@ namespace AndroidSideloader
|
||||
private Label activeMirrorLabel;
|
||||
private Label sideloadingStatusLabel;
|
||||
private Label rookieStatusLabel;
|
||||
private ModernListView _listViewRenderer;
|
||||
}
|
||||
}
|
||||
156
MainForm.cs
156
MainForm.cs
@@ -127,9 +127,18 @@ namespace AndroidSideloader
|
||||
gamesQueListBox.DataSource = gamesQueueList;
|
||||
SetCurrentLogPath();
|
||||
StartTimers();
|
||||
|
||||
lvwColumnSorter = new ListViewColumnSorter();
|
||||
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);
|
||||
|
||||
this.Resize += MainForm_Resize;
|
||||
@@ -2163,6 +2172,63 @@ namespace AndroidSideloader
|
||||
Logger.Log($"Cloud versions precomputed in {sw.ElapsedMilliseconds}ms");
|
||||
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
|
||||
await Task.Run(() =>
|
||||
{
|
||||
@@ -2179,7 +2245,28 @@ namespace AndroidSideloader
|
||||
|
||||
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;
|
||||
|
||||
if (installedVersions.TryGetValue(packagename, out ulong installedVersionInt))
|
||||
@@ -2231,10 +2318,43 @@ namespace AndroidSideloader
|
||||
}
|
||||
}
|
||||
|
||||
// Add the installed version to the ListView item
|
||||
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)
|
||||
@@ -4382,20 +4502,35 @@ If the problem persists, visit our Telegram (https://t.me/VRPirates) or Discord
|
||||
|
||||
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)
|
||||
{
|
||||
// Reverse the current sort direction for this column.
|
||||
lvwColumnSorter.Order = lvwColumnSorter.Order == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending;
|
||||
}
|
||||
else
|
||||
{
|
||||
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.
|
||||
|
||||
// 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)
|
||||
{
|
||||
@@ -7253,5 +7388,12 @@ function onYouTubeIframeAPIReady() {
|
||||
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
1232
ModernListView.cs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user