Skip to content

Commit 59736bc

Browse files
committed
feat: Add GitHubReleaseService & CheckForUpdatesBoxDialog
1 parent 7408e10 commit 59736bc

8 files changed

+220
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// ReSharper disable ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator
2+
namespace Atc.Installer.Integration;
3+
4+
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "OK.")]
5+
public class GitHubReleaseService : IGitHubReleaseService
6+
{
7+
private const string UserAgent = "Atc-Installer";
8+
private static readonly Uri ApiUri = new("https://api.github.com/repos/atc-net/atc-installer/releases/latest");
9+
10+
public async Task<Version?> GetLatestVersion()
11+
{
12+
try
13+
{
14+
using var client = new HttpClient();
15+
client.DefaultRequestHeaders.UserAgent.ParseAdd(UserAgent);
16+
var json = await client
17+
.GetStringAsync(ApiUri)
18+
.ConfigureAwait(false);
19+
20+
using var document = JsonDocument.Parse(json);
21+
var root = document.RootElement;
22+
var versionString = root.GetProperty("tag_name").ToString();
23+
24+
if (versionString.StartsWith("v", StringComparison.OrdinalIgnoreCase))
25+
{
26+
versionString = versionString[1..];
27+
}
28+
29+
return new Version(versionString);
30+
}
31+
catch
32+
{
33+
return null;
34+
}
35+
}
36+
37+
public async Task<Uri?> GetLatestMsiLink()
38+
{
39+
try
40+
{
41+
using var client = new HttpClient();
42+
client.DefaultRequestHeaders.UserAgent.ParseAdd(UserAgent);
43+
var json = await client
44+
.GetStringAsync(ApiUri)
45+
.ConfigureAwait(false);
46+
47+
using var document = JsonDocument.Parse(json);
48+
var root = document.RootElement;
49+
var assets = root.GetProperty("assets").EnumerateArray();
50+
foreach (var asset in assets)
51+
{
52+
if (asset.GetProperty("name").ToString().EndsWith(".msi", StringComparison.OrdinalIgnoreCase))
53+
{
54+
return new Uri(asset.GetProperty("browser_download_url").ToString());
55+
}
56+
}
57+
58+
return null;
59+
}
60+
catch
61+
{
62+
return null;
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Atc.Installer.Integration;
2+
3+
public interface IGitHubReleaseService
4+
{
5+
Task<Version?> GetLatestVersion();
6+
7+
Task<Uri?> GetLatestMsiLink();
8+
}

src/Atc.Installer.Wpf.App/Dialogs/AboutBoxDialog.xaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<TextBlock FontWeight="Bold" Text="Atc.Installer" />
2525
<StackPanel Orientation="Horizontal">
2626
<TextBlock Text="Version: " />
27-
<TextBlock x:Name="VersionTextBlock" Text="1.0.0" />
27+
<TextBlock x:Name="VersionTextBlock" Text="1.0.0.0" />
2828
</StackPanel>
2929
<TextBlock Text="© 2023 ATC" />
3030
</atc:UniformSpacingPanel>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<atc:NiceWindow
2+
x:Class="Atc.Installer.Wpf.App.Dialogs.CheckForUpdatesBoxDialog"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:atc="https://github.com/atc-net/atc-wpf/tree/main/schemas"
6+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
7+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
Title="Check for updates"
9+
Width="300"
10+
Height="250"
11+
Background="{DynamicResource AtcApps.Brushes.Dialog.Background}"
12+
ShowCloseButton="False"
13+
ShowMaxRestoreButton="False"
14+
ShowMinButton="False"
15+
WindowStartupLocation="CenterScreen"
16+
WindowStyle="SingleBorderWindow"
17+
mc:Ignorable="d">
18+
19+
<atc:GridEx Margin="20" Rows="*,Auto">
20+
<atc:UniformSpacingPanel
21+
Grid.Row="0"
22+
Orientation="Vertical"
23+
Spacing="20">
24+
25+
<TextBlock FontWeight="Bold" Text="Atc.Installer" />
26+
27+
<StackPanel Orientation="Horizontal">
28+
<TextBlock Text="Version: " />
29+
<TextBlock x:Name="VersionTextBlock" Text="1.0.0.0" />
30+
</StackPanel>
31+
32+
<StackPanel x:Name="NoVersionUpdatesContainer" Orientation="Horizontal">
33+
<TextBlock Text="No new updates." />
34+
</StackPanel>
35+
36+
<atc:UniformSpacingPanel
37+
x:Name="LatestVersionContainer"
38+
Orientation="Vertical"
39+
Spacing="20">
40+
<StackPanel Orientation="Horizontal">
41+
<TextBlock Foreground="DarkOrange" Text="Latest version: " />
42+
<TextBlock
43+
x:Name="LatestVersionTextBlock"
44+
Foreground="DarkOrange"
45+
Text="1.0.0.0" />
46+
</StackPanel>
47+
<TextBlock x:Name="LatestLinkTextBlock" HorizontalAlignment="Right">
48+
<Hyperlink
49+
x:Name="LatestVersionHyperlink"
50+
Click="OnLatestVersionHyperlinkClick"
51+
NavigateUri="...">
52+
<Run Text="Download latest MSI file" />
53+
</Hyperlink>
54+
</TextBlock>
55+
</atc:UniformSpacingPanel>
56+
57+
</atc:UniformSpacingPanel>
58+
<Button
59+
Grid.Row="1"
60+
Width="100"
61+
Margin="10"
62+
HorizontalAlignment="Right"
63+
Click="OnOk"
64+
Content="OK" />
65+
</atc:GridEx>
66+
67+
</atc:NiceWindow>
68+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// ReSharper disable InvertIf
2+
namespace Atc.Installer.Wpf.App.Dialogs;
3+
4+
/// <summary>
5+
/// Interaction logic for CheckForUpdatesBoxDialog.
6+
/// </summary>
7+
public partial class CheckForUpdatesBoxDialog
8+
{
9+
public CheckForUpdatesBoxDialog()
10+
{
11+
InitializeComponent();
12+
Loaded += OnLoaded;
13+
14+
VersionTextBlock.Text = Assembly
15+
.GetExecutingAssembly()
16+
.GetName()
17+
.Version!
18+
.ToString();
19+
20+
NoVersionUpdatesContainer.Visibility = Visibility.Visible;
21+
LatestVersionContainer.Visibility = Visibility.Collapsed;
22+
LatestLinkTextBlock.Visibility = Visibility.Collapsed;
23+
LatestVersionTextBlock.Text = VersionTextBlock.Text;
24+
}
25+
26+
private void OnLoaded(
27+
object sender,
28+
RoutedEventArgs e)
29+
{
30+
var gitHubReleaseService = new GitHubReleaseService();
31+
if (NetworkInformationHelper.HasConnection())
32+
{
33+
var version = TaskHelper.RunSync(() => gitHubReleaseService.GetLatestVersion());
34+
if (version is not null)
35+
{
36+
LatestVersionTextBlock.Text = version.ToString();
37+
var link = TaskHelper.RunSync(() => gitHubReleaseService.GetLatestMsiLink());
38+
LatestVersionHyperlink.NavigateUri = link;
39+
40+
var currentVersion = new Version(VersionTextBlock.Text);
41+
if (version.GreaterThan(currentVersion))
42+
{
43+
NoVersionUpdatesContainer.Visibility = Visibility.Collapsed;
44+
LatestVersionContainer.Visibility = Visibility.Visible;
45+
LatestLinkTextBlock.Visibility = Visibility.Visible;
46+
}
47+
}
48+
}
49+
}
50+
51+
private void OnLatestVersionHyperlinkClick(
52+
object sender,
53+
RoutedEventArgs e)
54+
{
55+
if (sender is System.Windows.Documents.Hyperlink latestVersionHyperlink &&
56+
latestVersionHyperlink.NavigateUri.IsAbsoluteUri)
57+
{
58+
InternetBrowserHelper.OpenUrl(latestVersionHyperlink.NavigateUri);
59+
}
60+
}
61+
62+
private void OnOk(
63+
object sender,
64+
RoutedEventArgs e)
65+
{
66+
Close();
67+
}
68+
}

src/Atc.Installer.Wpf.App/MainWindow.xaml

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
<MenuItem Command="{Binding Path=DownloadInstallationFilesFromAzureStorageAccountCommand}" Header="_Download components from Azure StorageAccount" />
5454
</MenuItem>
5555
<MenuItem Header="_Help">
56+
<MenuItem Command="{Binding Path=OpenApplicationCheckForUpdatesCommand}" Header="_Check for updates" />
5657
<MenuItem Command="{Binding Path=OpenApplicationAboutCommand}" Header="_About" />
5758
</MenuItem>
5859
</Menu>

src/Atc.Installer.Wpf.App/MainWindowProjectContent.xaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,12 @@
106106
<TextBlock
107107
Margin="20,0,0,0"
108108
FontSize="18"
109-
Foreground="Gold"
109+
Foreground="DarkOrange"
110110
Text="New version available" />
111111
<TextBlock
112112
Margin="10,0,0,0"
113113
FontSize="18"
114-
Foreground="Gold"
114+
Foreground="DarkOrange"
115115
Text="{Binding Path=SelectedComponentProvider.InstallationVersion}" />
116116
</StackPanel>
117117
</StackPanel>

src/Atc.Installer.Wpf.App/MainWindowViewModel_Commands.cs

+7
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ public IRelayCommandAsync DownloadInstallationFilesFromAzureStorageAccountComman
2323
DownloadInstallationFilesFromAzureStorageAccountCommandHandler,
2424
CanDownloadInstallationFilesFromAzureStorageAccountCommandHandler);
2525

26+
public static IRelayCommand OpenApplicationCheckForUpdatesCommand
27+
=> new RelayCommand(
28+
OpenApplicationCheckForUpdatesCommandHandler);
29+
2630
public static IRelayCommand OpenApplicationAboutCommand
2731
=> new RelayCommand(
2832
OpenApplicationAboutCommandHandler);
@@ -104,6 +108,9 @@ private async Task DownloadInstallationFilesFromAzureStorageAccountCommandHandle
104108
IsBusy = false;
105109
}
106110

111+
private static void OpenApplicationCheckForUpdatesCommandHandler()
112+
=> new CheckForUpdatesBoxDialog().ShowDialog();
113+
107114
private static void OpenApplicationAboutCommandHandler()
108115
=> new AboutBoxDialog().ShowDialog();
109116

0 commit comments

Comments
 (0)