diff --git a/Cursor_Installer_Creator.csproj b/Cursor_Installer_Creator.csproj index a9e86c4..a5b6239 100644 --- a/Cursor_Installer_Creator.csproj +++ b/Cursor_Installer_Creator.csproj @@ -1,7 +1,7 @@  WinExe - net8.0-windows + net9.0-windows7.0 enable true app.manifest @@ -24,15 +24,15 @@ - - - - + + + + - + - + \ No newline at end of file diff --git a/CCursor.cs b/Data/CCursor.cs similarity index 84% rename from CCursor.cs rename to Data/CCursor.cs index 45a4242..4f3d825 100644 --- a/CCursor.cs +++ b/Data/CCursor.cs @@ -1,6 +1,7 @@ -using System.IO; +using Cursor_Installer_Creator.Utils; +using System.IO; -namespace Cursor_Installer_Creator; +namespace Cursor_Installer_Creator.Data; public enum CCursorType { @@ -16,7 +17,7 @@ public sealed class CCursor public CCursorType GetCursorType() { - if (string.IsNullOrEmpty(CursorPath)) + if (string.IsNullOrWhiteSpace(CursorPath)) return CCursorType.unknown; if (CursorPath.EndsWith(".ani")) diff --git a/CursorAssignment.cs b/Data/CursorAssignment.cs similarity index 97% rename from CursorAssignment.cs rename to Data/CursorAssignment.cs index 7c37f4a..56c51e6 100644 --- a/CursorAssignment.cs +++ b/Data/CursorAssignment.cs @@ -5,7 +5,7 @@ using System.IO; using System.Linq; -namespace Cursor_Installer_Creator; +namespace Cursor_Installer_Creator.Data; public enum CursorAssignmentType { @@ -40,7 +40,7 @@ public static Dictionary ReadCsvString(string fileContent var dictionary = new Dictionary(); foreach (var record in records) { - if (string.IsNullOrEmpty(record.Name)) + if (string.IsNullOrWhiteSpace(record.Name)) continue; dictionary[record.ID] = record; } diff --git a/Data/Version.cs b/Data/Version.cs new file mode 100644 index 0000000..9059113 --- /dev/null +++ b/Data/Version.cs @@ -0,0 +1,101 @@ +using System; +using System.Linq; + +namespace Cursor_Installer_Creator.Data; + +public sealed class Version +{ + public int Major { get; set; } = -1; + public int Minor { get; set; } = -1; + public int Patch { get; set; } = -1; + public bool IsPrerelease { get; set; } + + public Version() { } + + public Version(int major, int minor, int patch, bool isPrerelease = false) + { + Major = major; + Minor = minor; + Patch = patch; + IsPrerelease = isPrerelease; + } + + public Version(string? version) + { + if (string.IsNullOrWhiteSpace(version)) + return; + + version = version.ToLower(); + version = version.TrimStart('v'); + + var parts = version.Split('-'); + IsPrerelease = parts.Length > 1; + + var versionParts = parts[0].Split('.').Select(int.Parse).ToArray(); + Major = versionParts[0]; + Minor = versionParts[1]; + Patch = versionParts[2]; + } + + public override string ToString() => IsPrerelease ? $"{Major}.{Minor}.{Patch}-alpha" : $"{Major}.{Minor}.{Patch}"; + + public override bool Equals(object? obj) + { + if (obj is Version otherVersion) + { + return Major == otherVersion.Major + && Minor == otherVersion.Minor + && Patch == otherVersion.Patch + && IsPrerelease == otherVersion.IsPrerelease; + } + return base.Equals(obj); + } + + public override int GetHashCode() => HashCode.Combine(Major, Minor, Patch, IsPrerelease); + + public static bool operator >(Version v1, Version v2) + { + if (v1.Major != v2.Major) + return v1.Major > v2.Major; + if (v1.Minor != v2.Minor) + return v1.Minor > v2.Minor; + if (v1.Patch != v2.Patch) + return v1.Patch > v2.Patch; + return !v1.IsPrerelease && v2.IsPrerelease; + } + + public static bool operator <(Version v1, Version v2) + { + return !(v1 > v2) && !v1.Equals(v2); + } + + public static bool operator >=(Version v1, Version v2) + { + return v1 > v2 || v1.Equals(v2); + } + + public static bool operator <=(Version v1, Version v2) + { + return v1 < v2 || v1.Equals(v2); + } + + public static Version operator +(Version v1, Version v2) + { + return new Version( + v1.Major + v2.Major, + v1.Minor + v2.Minor, + v1.Patch + v2.Patch, + v1.IsPrerelease || v2.IsPrerelease + ); + } + + public static Version operator -(Version v1, Version v2) + { + return new Version( + Math.Max(v1.Major - v2.Major, 0), + Math.Max(v1.Minor - v2.Minor, 0), + Math.Max(v1.Patch - v2.Patch, 0), + v1.IsPrerelease + ); + } +} diff --git a/CursorHelper.cs b/Utils/CursorHelper.cs similarity index 93% rename from CursorHelper.cs rename to Utils/CursorHelper.cs index c2c87db..2604c9b 100644 --- a/CursorHelper.cs +++ b/Utils/CursorHelper.cs @@ -1,4 +1,5 @@ -using Microsoft.Win32; +using Cursor_Installer_Creator.Data; +using Microsoft.Win32; using System; using System.Collections.Generic; using System.Diagnostics; @@ -11,7 +12,7 @@ using System.Text; using Cursor = System.Windows.Forms.Cursor; -namespace Cursor_Installer_Creator; +namespace Cursor_Installer_Creator.Utils; public static class CursorHelper { @@ -28,19 +29,17 @@ public static List GetSelectedCursors() foreach (var valueName in valueNames) { var cursorPath = key.GetValue(valueName)?.ToString(); - if (string.IsNullOrEmpty(cursorPath) || !File.Exists(cursorPath)) + if (string.IsNullOrWhiteSpace(cursorPath) || !File.Exists(cursorPath)) { var assignment = CursorAssignment.FromName(valueName, CursorAssignmentType.WindowsReg); - cursorPath = $"C:/Windows/Cursors/{assignment?.Windows}.cur"; + cursorPath = @$"C:\Windows\Cursors\{assignment?.Windows}.cur"; } if (File.Exists(cursorPath)) { var ccursor = ConvertCursorFile(cursorPath, valueName); if (ccursor is not null) - { ccursors.Add(ccursor); - } } } } @@ -58,9 +57,7 @@ public static List GetSelectedCursors() }; ccursor.CursorPath = ConvertCursorFile(ccursor.CursorPath, ccursor.Assignment)?.CursorPath ?? ccursor.CursorPath; if (File.Exists(ccursor.CursorPath)) - { ccursors.Add(ccursor); - } } } @@ -74,9 +71,7 @@ public static List GetSelectedCursors() { var cursorPath = key.GetValue(assignment.WindowsReg)?.ToString(); if (!File.Exists(cursorPath)) - { cursorPath = @$"C:\Windows\Cursors\{assignment.Windows}.cur"; - } return ConvertCursorFile(cursorPath, assignment.ID); } @@ -108,9 +103,7 @@ private static Dictionary ParseInstallerInfStrings(string filePa var value = parts[1].Trim().TrimStart('\"').TrimEnd('\"'); var assignment = CursorAssignment.FromName(key, CursorAssignmentType.WindowsInstall); if (assignment is not null) - { stringsDictionary[assignment.WindowsReg] = value; - } } } } @@ -129,9 +122,7 @@ public static IEnumerable CursorsFromInstallerInf(string filePath) { var ccursor = ConvertCursorFile(Path.Combine(Path.GetDirectoryName(filePath)!, kvp.Value), assignment); if (ccursor is not null) - { ccursors.Add(ccursor); - } } } return ccursors; @@ -163,9 +154,7 @@ public static void RemoveCursorDisplayImage(CCursor ccursor) { var prevCursorImagePath = Path.ChangeExtension(ccursor.CursorPath, ".png"); if (File.Exists(prevCursorImagePath)) - { File.Delete(prevCursorImagePath); - } } public static CCursor? ConvertCursorFile(string cursorPath, int cursorID) => ConvertCursorFile(cursorPath, CursorAssignment.CursorAssignments[cursorID]); @@ -188,9 +177,7 @@ public static void RemoveCursorDisplayImage(CCursor ccursor) var prevCursorImagePath = Path.ChangeExtension(destinationFullPath, ".png"); if (File.Exists(prevCursorImagePath)) - { File.Delete(prevCursorImagePath); - } var ccursor = new CCursor { @@ -207,24 +194,24 @@ public static void RemoveCursorDisplayImage(CCursor ccursor) } [DllImport("User32.dll", CharSet = CharSet.Unicode)] - private static extern IntPtr LoadCursorFromFile(string str); + private static extern nint LoadCursorFromFile(string str); private static Cursor GetCursorFromFile(string filename) { var hCursor = LoadCursorFromFile(filename); - return !IntPtr.Zero.Equals(hCursor) + return !nint.Zero.Equals(hCursor) ? new Cursor(hCursor) : throw new ApplicationException("Could not create cursor from file " + filename); } public static void CreateInstaller(string packageName, string folderPath, IEnumerable ccursors, bool createZip = true) { - using (var writer = new StreamWriter($"{Program.TempPath}/installer.inf")) + using (var writer = new StreamWriter(@$"{Program.TempPath}\installer.inf")) { writer.Write(CreateInstallerInfString(packageName, ccursors)); } var files = ccursors.Select(x => x.CursorPath).ToList(); - files.Add($"{Program.TempPath}/installer.inf"); + files.Add(@$"{Program.TempPath}\installer.inf"); if (createZip) { @@ -291,9 +278,7 @@ private static string CreateInstallerInfString(string packageName, IEnumerable files) { if (File.Exists(zipPath)) - { File.Delete(zipPath); - } using var archive = ZipFile.Open(zipPath, ZipArchiveMode.Create); var folder = Path.GetFileNameWithoutExtension(zipPath); foreach (var file in files) @@ -331,9 +316,7 @@ public static void InstallCursor(string installerFilePath) catch (System.ComponentModel.Win32Exception ex) { if (ex.NativeErrorCode != 1223) - { throw new Exception(ex.Message + Environment.NewLine + ex.ErrorCode); - } } } } diff --git a/Utils/GitHubUpdater.cs b/Utils/GitHubUpdater.cs new file mode 100644 index 0000000..c132db8 --- /dev/null +++ b/Utils/GitHubUpdater.cs @@ -0,0 +1,45 @@ +using Cursor_Installer_Creator.Data; +using System.Net.Http; +using System.Text.Json; +using System.Threading.Tasks; + +namespace Cursor_Installer_Creator.Utils; + +public sealed class GitHubUpdater +{ + public const string RepoOwner = "Der-Floh"; + public const string RepoName = "Cursor-Installer-Creator"; + + public static Version CurrentVersion { get; } = new Version(2, 1, 0); + public static string RepoUrl => $"https://github.com/{RepoOwner}/{RepoName}"; + public static string LatestReleaseUrl => $"https://github.com/{RepoOwner}/{RepoName}/releases/latest"; + + private static readonly HttpClient _client = new HttpClient(); + + public static async Task HasUpdateAsync() + { + try + { + // GitHub API endpoint for the latest release + var url = $"https://api.github.com/repos/{RepoOwner}/{RepoName}/releases/latest"; + _client.DefaultRequestHeaders.UserAgent.ParseAdd(RepoName.Replace('-', '_')); + + // Fetch latest release + var response = await _client.GetAsync(url); + response.EnsureSuccessStatusCode(); + + // Deserialize response + var jsonString = await response.Content.ReadAsStringAsync(); + var jsonDocument = JsonDocument.Parse(jsonString); + var latestVersionString = jsonDocument.RootElement.GetProperty("tag_name").GetString(); + var latestVersion = new Version(latestVersionString); + + // Compare versions + return latestVersion > CurrentVersion; + } + catch + { + return false; + } + } +} diff --git a/Views/CursorInstallerMainView.axaml b/Views/CursorInstallerMainView.axaml index 82840c3..1b9fdb0 100644 --- a/Views/CursorInstallerMainView.axaml +++ b/Views/CursorInstallerMainView.axaml @@ -13,7 +13,8 @@ - + + @@ -23,11 +24,11 @@ - + -