Skip to content

Commit 3910d2e

Browse files
committed
V2025.11.3
1 parent 9873ee4 commit 3910d2e

File tree

10 files changed

+132
-111
lines changed

10 files changed

+132
-111
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ MigrationBackup/
381381
FodyWeavers.xsd
382382

383383
# VS Code files for those working on multiple tools
384-
.vscode/*
384+
.vscode/
385385
!.vscode/settings.json
386386
!.vscode/tasks.json
387387
!.vscode/launch.json

Nickvision.Desktop.Tests/ServiceCollectionTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,8 @@ public void Case003_Add()
6666
{
6767
Assert.IsNotNull(_collection);
6868
var service = new TestService();
69-
Assert.IsTrue(_collection.Add<ITestService, TestService>(service));
70-
Assert.IsFalse(_collection.Add<ITestService, TestService>(service));
69+
Assert.IsTrue(_collection.Add<ITestService>(service));
70+
Assert.IsFalse(_collection.Add<ITestService>(service));
7171
Assert.IsTrue(_collection.Has<ITestService>());
7272
Assert.IsFalse(service.Disposed);
7373
}
@@ -95,7 +95,7 @@ public void Case006_Dispose()
9595
{
9696
Assert.IsNotNull(_collection);
9797
var service = new TestService();
98-
Assert.IsTrue(_collection.Add<ITestService, TestService>(service));
98+
Assert.IsTrue(_collection.Add<ITestService>(service));
9999
Assert.IsFalse(service.Disposed);
100100
_collection.Dispose();
101101
_collection = null;

Nickvision.Desktop/Application/AppInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public AppInfo(string id, string name, string englishShortName)
5454
/// <summary>
5555
/// The current running version of the app.
5656
/// </summary>
57-
public Version? Version { get; set; }
57+
public AppVersion? Version { get; set; }
5858

5959
/// <summary>
6060
/// The changelog of the app in Markdown format.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System;
2+
3+
namespace Nickvision.Desktop.Application;
4+
5+
public class AppVersion
6+
{
7+
public AppVersion(string version)
8+
{
9+
var dashIndex = version.IndexOf('-');
10+
version = version.TrimStart('v');
11+
if (!Version.TryParse(dashIndex == -1 ? version : version[..dashIndex], out var baseVersion))
12+
{
13+
throw new ArgumentException("Invalid version format", nameof(version));
14+
}
15+
BaseVersion = baseVersion;
16+
PreviewLabel = dashIndex == -1 ? string.Empty : version[(dashIndex + 1)..];
17+
}
18+
19+
public AppVersion(Version version)
20+
{
21+
BaseVersion = version;
22+
PreviewLabel = string.Empty;
23+
}
24+
25+
public Version BaseVersion { get; init; }
26+
public string PreviewLabel { get; init; }
27+
28+
public bool IsPreview => !string.IsNullOrEmpty(PreviewLabel);
29+
30+
public static bool TryParse(string version, out AppVersion? appVersion)
31+
{
32+
appVersion = null;
33+
try
34+
{
35+
appVersion = new AppVersion(version);
36+
return true;
37+
}
38+
catch
39+
{
40+
return false;
41+
}
42+
}
43+
44+
public static bool operator <(AppVersion? pv1, AppVersion? pv2)
45+
{
46+
if (pv1?.BaseVersion < pv2?.BaseVersion)
47+
{
48+
return true;
49+
}
50+
else if (pv1?.BaseVersion == pv2?.BaseVersion)
51+
{
52+
return string.Compare(pv1?.PreviewLabel, pv2?.PreviewLabel, StringComparison.Ordinal) < 0;
53+
}
54+
return false;
55+
}
56+
57+
public static bool operator <(AppVersion? pv, Version? v) => pv is null ? v is not null : pv.BaseVersion <= v;
58+
59+
public static bool operator >(AppVersion? pv1, AppVersion? pv2)
60+
{
61+
if (pv1 is null)
62+
{
63+
return pv2 is null;
64+
}
65+
if (pv1.BaseVersion > pv2?.BaseVersion)
66+
{
67+
return true;
68+
}
69+
if (pv1.BaseVersion == pv2?.BaseVersion)
70+
{
71+
return string.Compare(pv1.PreviewLabel, pv2?.PreviewLabel, StringComparison.Ordinal) > 0;
72+
}
73+
return false;
74+
}
75+
76+
public static bool operator >(AppVersion? pv, Version? v) => pv is null ? v is null : pv.BaseVersion > v;
77+
78+
public static bool operator ==(AppVersion? pv1, AppVersion? pv2) => pv1 is null ? pv2 is null : pv1.BaseVersion == pv2?.BaseVersion && pv1.PreviewLabel == pv2?.PreviewLabel;
79+
80+
public static bool operator ==(AppVersion? pv, Version? v) => pv is null ? v is null : pv.BaseVersion == v && string.IsNullOrEmpty(pv.PreviewLabel);
81+
82+
public static bool operator !=(AppVersion? pv1, AppVersion? pv2) => !(pv1 == pv2);
83+
84+
public static bool operator !=(AppVersion? pv, Version? v) => !(pv == v);
85+
86+
public override bool Equals(object? obj)
87+
{
88+
return obj switch
89+
{
90+
AppVersion pv => this == pv,
91+
Version v => this == v,
92+
var _ => false
93+
};
94+
}
95+
96+
public override int GetHashCode() => ToString().GetHashCode();
97+
98+
public override string ToString() => $"{BaseVersion}-{PreviewLabel}";
99+
}

Nickvision.Desktop/Application/GitHubUpdaterService.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public GitHubUpdaterService(AppInfo appInfo, HttpClient httpClient)
5858
/// <param name="exactMatch">Whether the asset name should match exactly to the asset to download</param>
5959
/// <param name="progress">An optional progress reporter</param>
6060
/// <returns></returns>
61-
public async Task<bool> DownloadReleaseAssetAsync(Version version,
61+
public async Task<bool> DownloadReleaseAssetAsync(AppVersion version,
6262
string path,
6363
string assertName,
6464
bool exactMatch = true,
@@ -69,7 +69,7 @@ public async Task<bool> DownloadReleaseAssetAsync(Version version,
6969
var releases = await _githubClient.Repository.Release.GetAll(_owner, _name);
7070
foreach (var release in releases)
7171
{
72-
if (!Version.TryParse(release.TagName.TrimStart('v'), out var releaseVersion))
72+
if (!AppVersion.TryParse(release.TagName.TrimStart('v'), out var releaseVersion))
7373
{
7474
continue;
7575
}
@@ -124,14 +124,14 @@ public async Task<bool> DownloadReleaseAssetAsync(Version version,
124124
/// Gets the latest preview version available.
125125
/// </summary>
126126
/// <returns>The latest preview version or null if unavailable</returns>
127-
public async Task<PreviewVersion?> GetLatestPreviewVersionAsync()
127+
public async Task<AppVersion?> GetLatestPreviewVersionAsync()
128128
{
129129
try
130130
{
131131
var releases = await _githubClient.Repository.Release.GetAll(_owner, _name);
132132
foreach (var release in releases.Where(r => r.Prerelease && !r.Draft))
133133
{
134-
if (!PreviewVersion.TryParse(release.TagName.TrimStart('v'), out var version))
134+
if (!AppVersion.TryParse(release.TagName, out var version))
135135
{
136136
continue;
137137
}
@@ -149,14 +149,14 @@ public async Task<bool> DownloadReleaseAssetAsync(Version version,
149149
/// Gets the latest stable version available.
150150
/// </summary>
151151
/// <returns>The latest stable version or null if unavailable</returns>
152-
public async Task<Version?> GetLatestStableVersionAsync()
152+
public async Task<AppVersion?> GetLatestStableVersionAsync()
153153
{
154154
try
155155
{
156156
var releases = await _githubClient.Repository.Release.GetAll(_owner, _name);
157157
foreach (var release in releases.Where(r => !r.Prerelease && !r.Draft))
158158
{
159-
if (!Version.TryParse(release.TagName.TrimStart('v'), out var version))
159+
if (!AppVersion.TryParse(release.TagName, out var version))
160160
{
161161
continue;
162162
}
@@ -176,7 +176,7 @@ public async Task<bool> DownloadReleaseAssetAsync(Version version,
176176
/// <param name="version">The released version</param>
177177
/// <param name="progress">An optional progress reporter</param>
178178
/// <returns>True if the update was downloaded and ran successfully, else false</returns>
179-
public async Task<bool> WindowsUpdate(Version version, IProgress<DownloadProgress>? progress = null)
179+
public async Task<bool> WindowsUpdate(AppVersion version, IProgress<DownloadProgress>? progress = null)
180180
{
181181
var setupPath = Path.Combine(UserDirectories.Cache, $"{_owner}_{_name}_Setup.exe");
182182
if (!await DownloadReleaseAssetAsync(version, setupPath, "setup.exe", false, progress))

Nickvision.Desktop/Application/IUpdaterService.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Nickvision.Desktop.Application;
77
/// <summary>
88
/// An interface of a service for updating an application.
99
/// </summary>
10-
public interface IUpdaterService
10+
public interface IUpdaterService : IService
1111
{
1212
/// <summary>
1313
/// Downloads an asset from a released version.
@@ -18,7 +18,7 @@ public interface IUpdaterService
1818
/// <param name="exactMatch">Whether the asset name should match exactly to the asset to download</param>
1919
/// <param name="progress">An optional progress reporter</param>
2020
/// <returns></returns>
21-
Task<bool> DownloadReleaseAssetAsync(Version version,
21+
Task<bool> DownloadReleaseAssetAsync(AppVersion version,
2222
string path,
2323
string assertName,
2424
bool exactMatch = true,
@@ -28,13 +28,13 @@ Task<bool> DownloadReleaseAssetAsync(Version version,
2828
/// Gets the latest preview version available.
2929
/// </summary>
3030
/// <returns>The latest preview version or null if unavailable</returns>
31-
Task<PreviewVersion?> GetLatestPreviewVersionAsync();
31+
Task<AppVersion?> GetLatestPreviewVersionAsync();
3232

3333
/// <summary>
3434
/// Gets the latest stable version available.
3535
/// </summary>
3636
/// <returns>The latest stable version or null if unavailable</returns>
37-
Task<Version?> GetLatestStableVersionAsync();
37+
Task<AppVersion?> GetLatestStableVersionAsync();
3838

3939
#if OS_WINDOWS
4040
/// <summary>
@@ -43,6 +43,6 @@ Task<bool> DownloadReleaseAssetAsync(Version version,
4343
/// <param name="version">The released version</param>
4444
/// <param name="progress">An optional progress reporter</param>
4545
/// <returns>True if the update was downloaded and ran successfully, else false</returns>
46-
Task<bool> WindowsUpdate(Version version, IProgress<DownloadProgress>? progress = null);
46+
Task<bool> WindowsUpdate(AppVersion version, IProgress<DownloadProgress>? progress = null);
4747
#endif
4848
}

Nickvision.Desktop/Application/PreviewVersion.cs

Lines changed: 0 additions & 89 deletions
This file was deleted.

Nickvision.Desktop/Application/ServiceCollection.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@ public void Dispose()
4040
/// <summary>
4141
/// Adds a service to the collection.
4242
/// </summary>
43-
/// <param name="implementation">The object of the service class</param>
43+
/// <param name="implementation">The object of the service interface</param>
4444
/// <typeparam name="T">The service interface</typeparam>
45-
/// <typeparam name="TU">The service class</typeparam>
4645
/// <returns></returns>
47-
public bool Add<T, TU>(TU implementation) where T : IService where TU : class, T => _services.TryAdd(typeof(T), implementation);
46+
public bool Add<T>(T implementation) where T : IService => _services.TryAdd(typeof(T), implementation);
4847

4948
/// <summary>
5049
/// Gets a service from the collection.

Nickvision.Desktop/Filesystem/JsonFileService.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System;
1+
using Nickvision.Desktop.Application;
2+
using System;
23
using System.IO;
34
using System.Text.Json;
45
using System.Threading.Tasks;
@@ -38,6 +39,17 @@ public JsonFileService(string directory)
3839
_directory = directory;
3940
}
4041

42+
/// <summary>
43+
/// Constructs a JsonFileService.
44+
/// </summary>
45+
/// <param name="appInfo">The AppInfo object for the app</param>
46+
/// <remarks>If the environment variable "{AppInfo.Id}.portable" is set, the current working directory will be used. Else, a {AppInfo.Name} folder will be created and used inside the user's configuration directory.</remarks>
47+
public JsonFileService(AppInfo appInfo)
48+
: this(Environment.GetEnvironmentVariable($"{appInfo.Id}.portable") is not null ? Directory.GetCurrentDirectory() : Path.Combine(UserDirectories.Config, appInfo.Name))
49+
{
50+
51+
}
52+
4153
/// <summary>
4254
/// Loads a json file and deserializes it into an object.
4355
/// </summary>

Nickvision.Desktop/Nickvision.Desktop.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
99
<EnableWindowsTargeting>true</EnableWindowsTargeting>
1010
<PackageId>Nickvision.Desktop</PackageId>
11-
<Version>2025.11.2</Version>
11+
<Version>2025.11.3</Version>
1212
<Company>Nickvision</Company>
1313
<Authors>Nickvision</Authors>
1414
<Description>A cross-platform base for Nickvision desktop applications.</Description>

0 commit comments

Comments
 (0)