Skip to content

Commit 727385c

Browse files
committed
feat: Improve CheckForUpdatesBoxDialog and added CheckForUpdatesBoxDialogViewModel
1 parent 59736bc commit 727385c

10 files changed

+203
-97
lines changed

src/Atc.Installer.Integration/GitHubReleaseService.cs

+27-3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ public class GitHubReleaseService : IGitHubReleaseService
1919

2020
using var document = JsonDocument.Parse(json);
2121
var root = document.RootElement;
22-
var versionString = root.GetProperty("tag_name").ToString();
22+
var versionString = root
23+
.GetProperty("tag_name")
24+
.ToString();
2325

2426
if (versionString.StartsWith("v", StringComparison.OrdinalIgnoreCase))
2527
{
@@ -46,10 +48,16 @@ public class GitHubReleaseService : IGitHubReleaseService
4648

4749
using var document = JsonDocument.Parse(json);
4850
var root = document.RootElement;
49-
var assets = root.GetProperty("assets").EnumerateArray();
51+
var assets = root
52+
.GetProperty("assets")
53+
.EnumerateArray();
54+
5055
foreach (var asset in assets)
5156
{
52-
if (asset.GetProperty("name").ToString().EndsWith(".msi", StringComparison.OrdinalIgnoreCase))
57+
if (asset
58+
.GetProperty("name")
59+
.ToString()
60+
.EndsWith(".msi", StringComparison.OrdinalIgnoreCase))
5361
{
5462
return new Uri(asset.GetProperty("browser_download_url").ToString());
5563
}
@@ -62,4 +70,20 @@ public class GitHubReleaseService : IGitHubReleaseService
6270
return null;
6371
}
6472
}
73+
74+
public async Task<byte[]> DownloadFileByLink(Uri uri)
75+
{
76+
try
77+
{
78+
using var client = new HttpClient();
79+
client.DefaultRequestHeaders.UserAgent.ParseAdd(UserAgent);
80+
return await client
81+
.GetByteArrayAsync(uri)
82+
.ConfigureAwait(false);
83+
}
84+
catch
85+
{
86+
return Array.Empty<byte>();
87+
}
88+
}
6589
}

src/Atc.Installer.Integration/IGitHubReleaseService.cs

+2
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ public interface IGitHubReleaseService
55
Task<Version?> GetLatestVersion();
66

77
Task<Uri?> GetLatestMsiLink();
8+
9+
Task<byte[]> DownloadFileByLink(Uri uri);
810
}

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ private void ConfigureServices(
5151
.AddOptions<ApplicationOptions>()
5252
.Bind(configuration!.GetRequiredSection(ApplicationOptions.SectionName));
5353

54+
services.AddSingleton<IGitHubReleaseService, GitHubReleaseService>();
5455
services.AddSingleton<INetworkShellService, NetworkShellService>();
5556
services.AddSingleton<IInstalledAppsInstallerService, InstalledAppsInstallerService>();
5657

@@ -60,7 +61,7 @@ private void ConfigureServices(
6061
services.AddSingleton<IWindowsApplicationInstallerService, WindowsApplicationInstallerService>();
6162
services.AddSingleton<IAzureStorageAccountInstallerService, AzureStorageAccountInstallerService>();
6263

63-
services.AddSingleton<IApplicationSettingsDialogViewModel, ApplicationSettingsDialogViewModel>();
64+
services.AddSingleton<ICheckForUpdatesBoxDialogViewModel, CheckForUpdatesBoxDialogViewModel>();
6465
services.AddSingleton<IMainWindowViewModelBase, MainWindowViewModel>();
6566
services.AddSingleton<MainWindow>();
6667
}

src/Atc.Installer.Wpf.App/Dialogs/ApplicationSettingsDialogViewModel.cs

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,16 @@ namespace Atc.Installer.Wpf.App.Dialogs;
22

33
public class ApplicationSettingsDialogViewModel : ViewModelBase, IApplicationSettingsDialogViewModel
44
{
5-
private readonly DirectoryInfo installerTempDirectory;
6-
75
public IRelayCommand<NiceWindow> OkCommand
86
=> new RelayCommand<NiceWindow>(
97
OkCommandCommandHandler);
108

119
public ApplicationSettingsDialogViewModel(
12-
ApplicationOptionsViewModel applicationOptionsViewModel,
13-
DirectoryInfo installerTempDirectory)
10+
ApplicationOptionsViewModel applicationOptionsViewModel)
1411
{
1512
ArgumentNullException.ThrowIfNull(applicationOptionsViewModel);
16-
ArgumentNullException.ThrowIfNull(installerTempDirectory);
1713

1814
this.ApplicationOptions = applicationOptionsViewModel;
19-
this.installerTempDirectory = installerTempDirectory;
2015

2116
ThemeManager.Current.ThemeChanged += OnThemeChanged;
2217
}

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

+29-31
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,26 @@
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
xmlns:atc="https://github.com/atc-net/atc-wpf/tree/main/schemas"
6+
xmlns:atcValueConverters="https://github.com/atc-net/atc-wpf/tree/main/schemas/value-converters"
67
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8+
xmlns:dialogs="clr-namespace:Atc.Installer.Wpf.App.Dialogs"
79
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
810
Title="Check for updates"
9-
Width="300"
11+
Width="350"
1012
Height="250"
11-
Background="{DynamicResource AtcApps.Brushes.Dialog.Background}"
13+
d:DataContext="{d:DesignInstance Type=dialogs:CheckForUpdatesBoxDialogViewModel}"
1214
ShowCloseButton="False"
1315
ShowMaxRestoreButton="False"
1416
ShowMinButton="False"
1517
WindowStartupLocation="CenterScreen"
1618
WindowStyle="SingleBorderWindow"
1719
mc:Ignorable="d">
1820

21+
<atc:NiceWindow.Resources>
22+
<atcValueConverters:BoolToVisibilityVisibleValueConverter x:Key="BoolToVisibilityVisibleValueConverter" />
23+
<atcValueConverters:BoolToVisibilityCollapsedValueConverter x:Key="BoolToVisibilityCollapsedValueConverter" />
24+
</atc:NiceWindow.Resources>
25+
1926
<atc:GridEx Margin="20" Rows="*,Auto">
2027
<atc:UniformSpacingPanel
2128
Grid.Row="0"
@@ -26,43 +33,34 @@
2633

2734
<StackPanel Orientation="Horizontal">
2835
<TextBlock Text="Version: " />
29-
<TextBlock x:Name="VersionTextBlock" Text="1.0.0.0" />
36+
<TextBlock Text="{Binding Path=CurrentVersion}" />
3037
</StackPanel>
3138

32-
<StackPanel x:Name="NoVersionUpdatesContainer" Orientation="Horizontal">
39+
<StackPanel Orientation="Horizontal" Visibility="{Binding Path=HasNewVersion, Converter={StaticResource BoolToVisibilityCollapsedValueConverter}, FallbackValue=True}">
3340
<TextBlock Text="No new updates." />
3441
</StackPanel>
3542

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>
43+
<StackPanel Orientation="Horizontal" Visibility="{Binding Path=HasNewVersion, Converter={StaticResource BoolToVisibilityVisibleValueConverter}}">
44+
<TextBlock Foreground="DarkOrange" Text="Latest version: " />
45+
<TextBlock Foreground="DarkOrange" Text="{Binding Path=LatestVersion}" />
46+
</StackPanel>
5647

5748
</atc:UniformSpacingPanel>
58-
<Button
49+
50+
<atc:GridEx
5951
Grid.Row="1"
60-
Width="100"
6152
Margin="10"
62-
HorizontalAlignment="Right"
63-
Click="OnOk"
64-
Content="OK" />
65-
</atc:GridEx>
53+
Columns="*,10,*">
54+
<Button
55+
Grid.Column="0"
56+
Command="{Binding Path=DownloadLatestCommand}"
57+
Content="Download Latest" />
58+
<Button
59+
Grid.Column="2"
60+
Click="OnOk"
61+
Content="OK" />
62+
</atc:GridEx>
6663

67-
</atc:NiceWindow>
64+
</atc:GridEx>
6865

66+
</atc:NiceWindow>

src/Atc.Installer.Wpf.App/Dialogs/CheckForUpdatesBoxDialog.xaml.cs

+3-49
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,11 @@ namespace Atc.Installer.Wpf.App.Dialogs;
66
/// </summary>
77
public partial class CheckForUpdatesBoxDialog
88
{
9-
public CheckForUpdatesBoxDialog()
9+
public CheckForUpdatesBoxDialog(
10+
ICheckForUpdatesBoxDialogViewModel viewModel)
1011
{
1112
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-
}
13+
DataContext = viewModel;
6014
}
6115

6216
private void OnOk(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
namespace Atc.Installer.Wpf.App.Dialogs;
2+
3+
public class CheckForUpdatesBoxDialogViewModel : ViewModelBase, ICheckForUpdatesBoxDialogViewModel
4+
{
5+
private readonly IGitHubReleaseService gitHubReleaseService;
6+
private string latestVersion = string.Empty;
7+
private string latestLink = string.Empty;
8+
private bool hasNewVersion;
9+
10+
public CheckForUpdatesBoxDialogViewModel(
11+
IGitHubReleaseService gitHubReleaseService)
12+
{
13+
this.gitHubReleaseService = gitHubReleaseService;
14+
15+
CurrentVersion = Assembly
16+
.GetExecutingAssembly()
17+
.GetName()
18+
.Version!
19+
.ToString();
20+
21+
LatestVersion = CurrentVersion;
22+
23+
TaskHelper.RunSync(RetrieveLatestFromGitHubHandler);
24+
}
25+
26+
public IRelayCommandAsync DownloadLatestCommand
27+
=> new RelayCommandAsync(
28+
DownloadLatestCommandHandler,
29+
CanDownloadLatestCommandHandler);
30+
31+
public string CurrentVersion { get; set; }
32+
33+
public string LatestVersion
34+
{
35+
get => latestVersion;
36+
set
37+
{
38+
latestVersion = value;
39+
RaisePropertyChanged();
40+
}
41+
}
42+
43+
public string LatestLink
44+
{
45+
get => latestLink;
46+
set
47+
{
48+
latestLink = value;
49+
RaisePropertyChanged();
50+
51+
HasNewVersion = false;
52+
if (Version.TryParse(CurrentVersion, out var cv) &&
53+
Version.TryParse(LatestVersion, out var lv))
54+
{
55+
HasNewVersion = lv.GreaterThan(cv);
56+
}
57+
}
58+
}
59+
60+
public bool HasNewVersion
61+
{
62+
get => hasNewVersion;
63+
set
64+
{
65+
hasNewVersion = value;
66+
RaisePropertyChanged();
67+
}
68+
}
69+
70+
private async Task RetrieveLatestFromGitHubHandler()
71+
{
72+
var version = await gitHubReleaseService
73+
.GetLatestVersion()
74+
.ConfigureAwait(true);
75+
76+
if (version is not null)
77+
{
78+
LatestVersion = version.ToString();
79+
var link = await gitHubReleaseService
80+
.GetLatestMsiLink()
81+
.ConfigureAwait(true);
82+
83+
if (link is not null)
84+
{
85+
LatestLink = link.AbsoluteUri;
86+
}
87+
}
88+
}
89+
90+
private bool CanDownloadLatestCommandHandler()
91+
=> HasNewVersion;
92+
93+
private async Task DownloadLatestCommandHandler()
94+
{
95+
var downloadBytes = await gitHubReleaseService
96+
.DownloadFileByLink(new Uri(LatestLink))
97+
.ConfigureAwait(true);
98+
99+
if (downloadBytes.Length > 0)
100+
{
101+
var saveFileDialog = new SaveFileDialog
102+
{
103+
FileName = "Atc.Installer.msi",
104+
};
105+
106+
if (saveFileDialog.ShowDialog() == true)
107+
{
108+
await File
109+
.WriteAllBytesAsync(saveFileDialog.FileName, downloadBytes)
110+
.ConfigureAwait(true);
111+
}
112+
}
113+
}
114+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
namespace Atc.Installer.Wpf.App.Dialogs;
2+
3+
public interface ICheckForUpdatesBoxDialogViewModel
4+
{
5+
}

0 commit comments

Comments
 (0)