Files
rookie/DonorsListView.cs
jp64k 1bcfbd132d Updated icon in forms I missed earlier; now reusing existing icon; dropping .exe size from 3,38 MB to 1,03 MB
Updated icon in forms I missed earlier; now reusing existing icon; dropping .exe size from 3,38 MB to 1,03 MB
2025-12-17 22:18:19 +01:00

324 lines
12 KiB
C#

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);
}
}
}
}