diff --git a/PostCodeSerialMonitor/Assets/Resources.Designer.cs b/PostCodeSerialMonitor/Assets/Resources.Designer.cs
index 755ef01..03b363c 100644
--- a/PostCodeSerialMonitor/Assets/Resources.Designer.cs
+++ b/PostCodeSerialMonitor/Assets/Resources.Designer.cs
@@ -176,7 +176,25 @@ public static string FailedDownloadMetaDefinition {
return ResourceManager.GetString("FailedDownloadMetaDefinition", resourceCulture);
}
}
+
+ ///
+ /// In Services/MetaUpdateService.cs
+ ///
+ public static string FailedDeserializingReleaseDefinition {
+ get {
+ return ResourceManager.GetString("FailedDeserializingReleaseDefinition", resourceCulture);
+ }
+ }
+ ///
+ /// In Services/MetaUpdateService.cs
+ ///
+ public static string FailedDownloadReleaseDefinition {
+ get {
+ return ResourceManager.GetString("FailedDownloadReleaseDefinition", resourceCulture);
+ }
+ }
+
///
/// In Services/SerialLineDecoder.cs
///
@@ -302,7 +320,25 @@ public static string FailedUpdateMetadata {
return ResourceManager.GetString("FailedUpdateMetadata", resourceCulture);
}
}
-
+
+ ///
+ /// In ViewModels/MainWindowViewModel.cs
+ ///
+ public static string NewAppReleaseAvailable {
+ get {
+ return ResourceManager.GetString("NewAppReleaseAvailable", resourceCulture);
+ }
+ }
+
+ ///
+ /// In ViewModels/MainWindowViewModel.cs
+ ///
+ public static string NewFirmwareReleaseAvailable {
+ get {
+ return ResourceManager.GetString("NewFirmwareReleaseAvailable", resourceCulture);
+ }
+ }
+
///
/// In ViewModels/MainWindowViewModel.cs
///
diff --git a/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx b/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx
index 8195cca..9afb5d7 100644
--- a/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx
+++ b/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx
@@ -169,6 +169,14 @@
Falha ao baixar MetaDefinition de {0}
In Services/MetaUpdateService.cs
+
+ Falha ao deserializar ReleaseDefinition
+ In Services/MetaUpdateService.cs
+
+
+ Falha ao baixar o último lançamento de {0}
+ In Services/MetaUpdateService.cs
+
Decodificador: Ignorando linha {0}
In Services/SerialLineDecoder.cs
@@ -225,6 +233,14 @@
Falha ao ataulizar o metadata
In ViewModels/MainWindowViewModel.cs
+
+ Uma nova versão do aplicativo está disponível em {0}.
+ In ViewModels/MainWindowViewModel.cs
+
+
+ Uma nova versão do firmware está disponível em {0}.
+ In ViewModels/MainWindowViewModel.cs
+
Erro
In ViewModels/MainWindowViewModel.cs
diff --git a/PostCodeSerialMonitor/Assets/Resources.resx b/PostCodeSerialMonitor/Assets/Resources.resx
index 0336470..ca22351 100644
--- a/PostCodeSerialMonitor/Assets/Resources.resx
+++ b/PostCodeSerialMonitor/Assets/Resources.resx
@@ -169,6 +169,14 @@
Failed to download MetaDefinition from {0}
In Services/MetaUpdateService.cs
+
+ Failed deserializing ReleaseDefinition
+ In Services/MetaUpdateService.cs
+
+
+ Failed to download latest release from {0}
+ In Services/MetaUpdateService.cs
+
Decoder: Ignoring line {0}
In Services/SerialLineDecoder.cs
@@ -225,6 +233,14 @@
Failed to update metadata
In ViewModels/MainWindowViewModel.cs
+
+ A new app release is available at {0}.
+ In ViewModels/MainWindowViewModel.cs
+
+
+ A new firmware release is available at {0}.
+ In ViewModels/MainWindowViewModel.cs
+
Error
In ViewModels/MainWindowViewModel.cs
diff --git a/PostCodeSerialMonitor/Models/ReleaseDefinition.cs b/PostCodeSerialMonitor/Models/ReleaseDefinition.cs
new file mode 100644
index 0000000..2298b2a
--- /dev/null
+++ b/PostCodeSerialMonitor/Models/ReleaseDefinition.cs
@@ -0,0 +1,5 @@
+namespace PostCodeSerialMonitor.Models;
+public class ReleaseDefinition
+{
+ public string tag_name { get; set; } = string.Empty;
+}
\ No newline at end of file
diff --git a/PostCodeSerialMonitor/Services/MetaUpdateService.cs b/PostCodeSerialMonitor/Services/MetaUpdateService.cs
index 0204cd9..ab2e516 100644
--- a/PostCodeSerialMonitor/Services/MetaUpdateService.cs
+++ b/PostCodeSerialMonitor/Services/MetaUpdateService.cs
@@ -1,13 +1,16 @@
using System;
using System.IO;
using System.Net.Http;
+using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using PostCodeSerialMonitor.Models;
+using PostCodeSerialMonitor.Utils;
using Microsoft.Extensions.Logging;
namespace PostCodeSerialMonitor.Services;
+
public class MetaUpdateService
{
private readonly ConfigurationService _configurationService;
@@ -24,8 +27,8 @@ public class MetaUpdateService
public AppConfiguration Config => _configurationService.Config;
public MetaUpdateService(
- ConfigurationService configurationService,
- JsonSerializerOptions jsonOptions,
+ ConfigurationService configurationService,
+ JsonSerializerOptions jsonOptions,
ILogger logger)
{
_configurationService = configurationService ?? throw new ArgumentNullException(nameof(configurationService));
@@ -34,6 +37,10 @@ public MetaUpdateService(
?? throw new ArgumentNullException(nameof(_configurationService.Config.MetaStoragePath));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_httpClient = new HttpClient();
+
+ //All GitHub's API requests must include a valid User-Agent header.
+ //@see https://docs.github.com/en/rest/using-the-rest-api/getting-started-with-the-rest-api?apiVersion=2022-11-28#user-agent
+ _httpClient.DefaultRequestHeaders.Add("User-Agent", "XboxPostcodeMonitor");
}
public async Task TryLoadLocalDefinition()
@@ -46,11 +53,35 @@ public async Task TryLoadLocalDefinition()
return true;
}
+ public async Task CheckForAppUpdatesAsync(string localVersion)
+ {
+ // Get the latest release from GitHub repo.
+ var remoteRelease = await GetRepositoryLatestReleaseAsync("xboxoneresearch", "XboxPostcodeMonitor");
+ var remoteVersion = (remoteRelease == null) ? string.Empty : remoteRelease.tag_name;
+
+ SemanticVersionUtils local = new SemanticVersionUtils(localVersion);
+ SemanticVersionUtils remote = new SemanticVersionUtils(remoteVersion);
+
+ return remote > local;
+ }
+
+ public async Task CheckForFirmwareUpdatesAsync(string localVersion)
+ {
+ // Get the latest release from GitHub repo.
+ var remoteRelease = await GetRepositoryLatestReleaseAsync("xboxoneresearch", "PicoDurangoPOST");
+ var remoteVersion = (remoteRelease == null) ? string.Empty : remoteRelease.tag_name;
+
+ SemanticVersionUtils local = new SemanticVersionUtils(localVersion);
+ SemanticVersionUtils remote = new SemanticVersionUtils(remoteVersion);
+
+ return remote > local;
+ }
+
public async Task CheckForMetaDefinitionUpdatesAsync()
{
var localMeta = await GetLocalMetaDefinitionAsync();
var remoteMeta = await GetRemoteMetaDefinitionAsync();
-
+
if (localMeta == null || remoteMeta == null)
{
// Update required
@@ -75,7 +106,7 @@ public async Task UpdateMetaDefinitionAsync()
// Ensure directory exists
Directory.CreateDirectory(_localPath);
-
+
// Save the new meta definition
await File.WriteAllTextAsync(LocalMetaPath, metaContentStr);
@@ -143,7 +174,7 @@ private async Task DownloadMetaFilesAsync()
{
var response = await _httpClient.GetAsync(Config.MetaJsonUrl);
response.EnsureSuccessStatusCode();
-
+
var json = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize(json, _jsonSerializeOptions);
}
@@ -153,4 +184,23 @@ private async Task DownloadMetaFilesAsync()
return null;
}
}
+
+ private async Task GetRepositoryLatestReleaseAsync(string owner, string repo)
+ {
+ var gitHubApiReleasesLatest = new Uri($"https://api.github.com/repos/{owner}/{repo}/releases/latest");
+
+ try
+ {
+ var response = await _httpClient.GetAsync(gitHubApiReleasesLatest);
+ response.EnsureSuccessStatusCode();
+
+ var json = await response.Content.ReadAsStringAsync();
+ return JsonSerializer.Deserialize(json, _jsonSerializeOptions);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, Assets.Resources.FailedDownloadReleaseDefinition, gitHubApiReleasesLatest);
+ return null;
+ }
+ }
}
\ No newline at end of file
diff --git a/PostCodeSerialMonitor/Utils/SemanticVersionUtils.cs b/PostCodeSerialMonitor/Utils/SemanticVersionUtils.cs
new file mode 100644
index 0000000..aa700a8
--- /dev/null
+++ b/PostCodeSerialMonitor/Utils/SemanticVersionUtils.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using Avalonia.X11.Interop;
+
+namespace PostCodeSerialMonitor.Utils;
+
+public class SemanticVersionUtils
+{
+ private string _version { get; set; } = string.Empty;
+
+ public SemanticVersionUtils(string version)
+ {
+ //Ignore the 'v' at the beginning of the version string
+ if (version.StartsWith("v"))
+ {
+ _version = version.Substring(1);
+ }
+ else
+ {
+ _version = version;
+ }
+ }
+
+ /// Override greater-than operator for SemanticVersionUtils
+ public static bool operator >(SemanticVersionUtils left, SemanticVersionUtils right)
+ {
+ return string.Compare(left._version, right._version) > 0;
+ }
+
+ /// Override less-than operator for SemanticVersionUtils
+ public static bool operator <(SemanticVersionUtils left, SemanticVersionUtils right)
+ {
+ return string.Compare(left._version, right._version) < 0;
+ }
+}
\ No newline at end of file
diff --git a/PostCodeSerialMonitor/ViewModels/MainWindowViewModel.cs b/PostCodeSerialMonitor/ViewModels/MainWindowViewModel.cs
index aa01310..3c02046 100644
--- a/PostCodeSerialMonitor/ViewModels/MainWindowViewModel.cs
+++ b/PostCodeSerialMonitor/ViewModels/MainWindowViewModel.cs
@@ -174,6 +174,19 @@ await MessageBoxManager
ButtonEnum.Ok)
.ShowAsync();
}
+
+ if (_configurationService.Config.CheckForAppUpdates)
+ {
+ updateAvailable = await _metaUpdateService.CheckForAppUpdatesAsync(AppVersion);
+ if (updateAvailable)
+ {
+ var box = MessageBoxManager
+ .GetMessageBoxStandard(Assets.Resources.Warning,
+ string.Format(Assets.Resources.NewAppReleaseAvailable, "https://github.com/xboxoneresearch/XboxPostcodeMonitor/releases"), ButtonEnum.Ok);
+
+ await box.ShowAsync();
+ }
+ }
}
[RelayCommand]
@@ -267,10 +280,23 @@ private async Task ConnectAsync()
{
_logger.LogError(ex, Assets.Resources.ErrorConection);
await MessageBoxManager
- .GetMessageBoxStandard(Assets.Resources.Error, string.Format(Assets.Resources.ErrorConectionMessageBoxError,ex.Message),
+ .GetMessageBoxStandard(Assets.Resources.Error, string.Format(Assets.Resources.ErrorConectionMessageBoxError, ex.Message),
ButtonEnum.Ok)
.ShowAsync();
}
+
+ if (IsConnected && _configurationService.Config.CheckForFwUpdates)
+ {
+ var updateAvailable = await _metaUpdateService.CheckForFirmwareUpdatesAsync(_serialService.FirmwareVersion);
+ if (updateAvailable)
+ {
+ var box = MessageBoxManager
+ .GetMessageBoxStandard(Assets.Resources.Warning,
+ string.Format(Assets.Resources.NewFirmwareReleaseAvailable, "https://github.com/xboxoneresearch/PicoDurangoPOST/releases"), ButtonEnum.Ok);
+
+ await box.ShowAsync();
+ }
+ }
}
}