mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-09-16 05:19:23 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef4befdc38 | ||
|
|
33f49ddffa | ||
|
|
49aa249b5b |
+24
-38
@@ -5,12 +5,11 @@
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: Daybreak CD Pipeline
|
||||
|
||||
# Trigger on every master branch push and pull request
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
@@ -26,76 +25,63 @@ jobs:
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreal.csproj
|
||||
Actions_Allow_Unsecure_Commands: true # Allows AddPAth and SetEnv commands
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Latest Tag
|
||||
id: getLatestTag
|
||||
uses: WyriHaximus/github-action-get-previous-tag@v1
|
||||
|
||||
- name: Generate changelog
|
||||
id: gen_changelog
|
||||
run: |
|
||||
$changeLog = git log --no-merges --pretty="%h - %s (%an)<br />" ${{ env.LatestReleaseTag }}..HEAD
|
||||
echo "::set-env name=Changelog::$changeLog"
|
||||
env:
|
||||
LatestReleaseTag: ${{steps.getLatestTag.outputs.tag}}
|
||||
|
||||
- name: Print changelog
|
||||
run: |
|
||||
echo "${{ env.Changelog }}"
|
||||
|
||||
# Install the .NET Core workload
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.202'
|
||||
|
||||
# Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
# Restore the application
|
||||
- name: Restore the Wpf application to populate the obj folder
|
||||
- name: Restore project
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
# Build Daybreak project
|
||||
- name: Build Daybreak project
|
||||
run: dotnet build Daybreak -c $env:Configuration
|
||||
|
||||
# Set release version environment variable
|
||||
- name: Set version variable
|
||||
run: |
|
||||
$version = .\Scripts\GetBuildVersion.ps1
|
||||
echo "::set-env name=Version::$version"
|
||||
|
||||
# Publish release
|
||||
- name: Publish release
|
||||
- name: Create publish files
|
||||
run: dotnet publish .\Daybreak\Daybreak.csproj -c $env:Configuration -r $env:RuntimeIdentifier -p:PublishReadyToRun=true -p:PublishSingleFile=true --self-contained true -o .\Publish
|
||||
env:
|
||||
RuntimeIdentifier: win-${{ matrix.targetplatform }}
|
||||
|
||||
# Create release payload
|
||||
- name: Create release payload
|
||||
- name: Pack publish files
|
||||
run: |
|
||||
Write-Host $env
|
||||
.\Scripts\BuildRelease.ps1 -version $env:Version
|
||||
shell: pwsh
|
||||
|
||||
# Get latest release
|
||||
- name: Get latest release tag
|
||||
id: download_release
|
||||
uses: Xotl/cool-github-releases@v1.1.2
|
||||
with:
|
||||
mode: download
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Generate changelog
|
||||
- name: Generate changelog
|
||||
id: gen_changelog
|
||||
uses: mikepenz/release-changelog-builder-action@v1.8.0
|
||||
with:
|
||||
fromTag: ${{ steps.download_release.outputs.tag_name }}
|
||||
toTag: ${{ env.Version }}
|
||||
token: ${{ env.GITHUB_TOKEN }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Post new release to github
|
||||
- name: Post release
|
||||
- name: Publish release
|
||||
uses: Xotl/cool-github-releases@v1.1.2
|
||||
with:
|
||||
mode: update
|
||||
@@ -104,7 +90,7 @@ jobs:
|
||||
assets: .\Publish\daybreakv${{ env.Version }}.zip
|
||||
github_token: ${{ env.GITHUB_TOKEN }}
|
||||
replace_assets: true
|
||||
body_mrkdwn: ${{ steps.gen_changelog.outputs.changelog }}
|
||||
body_mrkdwn: ${{ env.Changelog }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
# This pipeline builds the Wpf project, runs unit tests, then saves the MSIX build artifact.
|
||||
name: Daybreak CI Pipeline
|
||||
|
||||
# Trigger on every master branch push and pull request
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -28,29 +27,25 @@ jobs:
|
||||
Solution_Path: Daybreak.sln
|
||||
Test_Project_Path: Daybreak.Tests\Daybreak.Tests.csproj
|
||||
Wpf_Project_Path: Daybreak\Daybreal.csproj
|
||||
Actions_Allow_Unsecure_Commands: true # Allows AddPAth and SetEnv commands
|
||||
Actions_Allow_Unsecure_Commands: true
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
|
||||
fetch-depth: 0
|
||||
|
||||
# Install the .NET Core workload
|
||||
- name: Install .NET Core
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: '5.0.202'
|
||||
|
||||
# Add MsBuild to the PATH: https://github.com/microsoft/setup-msbuild
|
||||
- name: Setup MSBuild.exe
|
||||
uses: microsoft/setup-msbuild@v1.0.1
|
||||
|
||||
# Test
|
||||
- name: Execute Unit Tests
|
||||
run: dotnet test $env:Test_Project_Path
|
||||
|
||||
# Restore the application
|
||||
- name: Restore the Wpf application to populate the obj folder
|
||||
run: msbuild $env:Solution_Path /t:Restore /p:Configuration=$env:Configuration /p:RuntimeIdentifier=$env:RuntimeIdentifier
|
||||
env:
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
using Daybreak.Models.Versioning;
|
||||
using FluentAssertions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Version = Daybreak.Models.Versioning.Version;
|
||||
|
||||
namespace Daybreak.Tests.Models
|
||||
{
|
||||
[TestClass]
|
||||
public class VersionTests
|
||||
{
|
||||
[DataRow("v0.1.0", "v0.1")]
|
||||
[DataRow("0.1.0", "0.1")]
|
||||
[DataRow("v0.1.0.0.0", "v0.1")]
|
||||
[DataRow("0.1.0.0.0", "0.1")]
|
||||
[DataRow("v0", "v0")]
|
||||
[DataRow("0", "0")]
|
||||
[DataRow("v0.1", "v0.1")]
|
||||
[DataRow("0.1-release", "0.1-release")]
|
||||
[DataRow("v0.1-release", "v0.1-release")]
|
||||
[TestMethod]
|
||||
public void VersionToString(string version, string expectedString)
|
||||
{
|
||||
var parsedVersion = Version.Parse(version);
|
||||
parsedVersion.ToString().Should().Be(expectedString);
|
||||
}
|
||||
|
||||
[DataRow("v0", false)]
|
||||
[DataRow("0", false)]
|
||||
[DataRow("v0.1", false)]
|
||||
[DataRow("0.1-release", true)]
|
||||
[DataRow("v0.1-release", true)]
|
||||
[TestMethod]
|
||||
public void VersionHasStringSuffix(string version, bool hasSuffix)
|
||||
{
|
||||
var parsedVersion = Version.Parse(version);
|
||||
if (hasSuffix)
|
||||
{
|
||||
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionStringToken>();
|
||||
}
|
||||
else
|
||||
{
|
||||
parsedVersion.VersionTokens.Last().Should().BeOfType<VersionNumberToken>();
|
||||
}
|
||||
}
|
||||
|
||||
[DataRow("v0", true)]
|
||||
[DataRow("0", false)]
|
||||
[DataRow("v0.1", true)]
|
||||
[DataRow("0.1", false)]
|
||||
[TestMethod]
|
||||
public void VersionTokensHasPrefix(string version, bool hasPrefix)
|
||||
{
|
||||
var parsedVersion = Version.Parse(version);
|
||||
parsedVersion.HasPrefix.Should().Be(hasPrefix);
|
||||
}
|
||||
|
||||
[DataRow(null, false)]
|
||||
[DataRow("", false)]
|
||||
[DataRow("asd", false)]
|
||||
[DataRow("ads.pls.er", false)]
|
||||
[DataRow("0.0.1", true)]
|
||||
[DataRow("1", true)]
|
||||
[DataRow("0.1.asd", false)]
|
||||
[DataRow("0.", false)]
|
||||
[DataRow(".1", false)]
|
||||
[DataRow("0.1-", false)]
|
||||
[DataRow("0.1-release", true)]
|
||||
[DataRow("0..1", false)]
|
||||
[TestMethod]
|
||||
public void TryParseVersionTest(string version, bool result)
|
||||
{
|
||||
var success = Version.TryParse(version, out var parsedVersion);
|
||||
success.Should().Be(result);
|
||||
if (success is true)
|
||||
{
|
||||
parsedVersion.Should().NotBeNull();
|
||||
}
|
||||
}
|
||||
|
||||
[DataRow(null, false)]
|
||||
[DataRow("", false)]
|
||||
[DataRow("asd", false)]
|
||||
[DataRow("ads.pls.er", false)]
|
||||
[DataRow("0.0.1", true)]
|
||||
[DataRow("1", true)]
|
||||
[DataRow("0.1.asd", false)]
|
||||
[DataRow("0.", false)]
|
||||
[DataRow(".1", false)]
|
||||
[DataRow("0.1-", false)]
|
||||
[DataRow("0.1-release", true)]
|
||||
[DataRow("0..1", false)]
|
||||
[TestMethod]
|
||||
public void ParseVersionTest(string version, bool shouldNotThrow)
|
||||
{
|
||||
var action = new Action(() => Version.Parse(version));
|
||||
if (shouldNotThrow is false)
|
||||
{
|
||||
action.Should().Throw<InvalidOperationException>();
|
||||
}
|
||||
else
|
||||
{
|
||||
action.Should().NotThrow<InvalidOperationException>();
|
||||
}
|
||||
}
|
||||
|
||||
[DataRow(null, false)]
|
||||
[DataRow("", false)]
|
||||
[DataRow("asd", false)]
|
||||
[DataRow("ads.pls.er", false)]
|
||||
[DataRow("0.0.1", true)]
|
||||
[DataRow("1", true)]
|
||||
[DataRow("0.1.asd", false)]
|
||||
[DataRow("0.", false)]
|
||||
[DataRow(".1", false)]
|
||||
[DataRow("0.1-", false)]
|
||||
[DataRow("0.1-release", true)]
|
||||
[DataRow("0..1", false)]
|
||||
[TestMethod]
|
||||
public void VersionConstructorTest(string version, bool shouldNotThrow)
|
||||
{
|
||||
var action = new Action(() => new Version(version));
|
||||
if (shouldNotThrow is false)
|
||||
{
|
||||
action.Should().Throw<ArgumentException>();
|
||||
}
|
||||
else
|
||||
{
|
||||
action.Should().NotThrow<ArgumentException>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,5 +35,7 @@ namespace Daybreak.Configuration
|
||||
public string ShortcutLocation { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
|
||||
[JsonProperty("PlaceShortcut")]
|
||||
public bool PlaceShortcut { get; set; }
|
||||
[JsonProperty("AutoCheckUpdate")]
|
||||
public bool AutoCheckUpdate { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace Daybreak.Configuration
|
||||
viewProducer.RegisterView<BuildsListView>();
|
||||
viewProducer.RegisterView<RequestElevationView>();
|
||||
viewProducer.RegisterView<ScreenChoiceView>();
|
||||
viewProducer.RegisterView<VersionManagementView>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<UserControl x:Class="Daybreak.Controls.StaticGlyph"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Viewbox>
|
||||
<Polygon Fill="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Points="209.89999389648438,829.800048828125 279.1999816894531,493.9000244140625 0,493.9000244140625 415.89996337890625,0 346.699951171875,335.8999938964844 625.800048828125,335.8999938964844"></Polygon>
|
||||
</Viewbox>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for StaticGlyph.xaml
|
||||
/// </summary>
|
||||
public partial class StaticGlyph : UserControl
|
||||
{
|
||||
public StaticGlyph()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ApplicationIcon>Daybreak.ico</ApplicationIcon>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<Version>0.8.8</Version>
|
||||
<Version>0.8.9</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -65,7 +65,7 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(Configuration)' == 'Release'">
|
||||
<Exec Command="echo.>$(Version).version" />
|
||||
</Target>
|
||||
|
||||
|
||||
@@ -86,15 +86,18 @@
|
||||
HorizontalAlignment="Right" Margin="0, 0, 20, 30" FontSize="22" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Clicked="CreditTextBox_MouseLeftButtonDown" Cursor="Hand"></controls:OpaqueButton>
|
||||
<WrapPanel Grid.Row="1" Margin="0, 0, 20, 10" VerticalAlignment="Bottom" HorizontalAlignment="Right">
|
||||
<TextBox Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
|
||||
Text="{Binding ElementName=_this, Path=CurrentVersionText, Mode=OneWay}" IsReadOnly="True" FontSize="10"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"></TextBox>
|
||||
<TextBox Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
<controls:OpaqueButton Grid.Row="1" Background="Transparent" BorderBrush="Transparent" BorderThickness="0" Opacity="0.6"
|
||||
Text="{Binding ElementName=_this, Path=CurrentVersionText, Mode=OneWay}" FontSize="10"
|
||||
Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Clicked="VersionText_Clicked"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Opacity="0.6" Text=" - " FontSize="10" BorderBrush="Transparent" BorderThickness="0"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></TextBox>
|
||||
<TextBox Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Clicked="VersionText_Clicked"></controls:OpaqueButton>
|
||||
<controls:OpaqueButton Grid.Row="1" Background="Transparent" Foreground="{Binding ElementName=_this, Path=Foreground, Mode=OneWay}"
|
||||
Opacity="0.6" Text="[Admin]" FontSize="10" BorderBrush="Transparent" BorderThickness="0"
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"></TextBox>
|
||||
Visibility="{Binding ElementName=_this, Path=IsRunningAsAdmin, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Clicked="VersionText_Clicked"></controls:OpaqueButton>
|
||||
</WrapPanel>
|
||||
<Grid x:Name="Container" Grid.Row="1">
|
||||
</Grid>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Daybreak.Services.Bloogum;
|
||||
using Daybreak.Services.Configuration;
|
||||
using Daybreak.Services.Privilege;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.Screenshots;
|
||||
@@ -31,8 +32,11 @@ namespace Daybreak.Launch
|
||||
private readonly IBloogumClient bloogumClient;
|
||||
private readonly IApplicationUpdater applicationUpdater;
|
||||
private readonly IPrivilegeManager privilegeManager;
|
||||
private readonly IConfigurationManager configurationManager;
|
||||
private readonly CancellationTokenSource cancellationToken = new();
|
||||
|
||||
private bool canCheckUpdate = false;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private string creditText;
|
||||
[GenerateDependencyProperty]
|
||||
@@ -45,18 +49,28 @@ namespace Daybreak.Launch
|
||||
IScreenshotProvider screenshotProvider,
|
||||
IBloogumClient bloogumClient,
|
||||
IApplicationUpdater applicationUpdater,
|
||||
IPrivilegeManager privilegeManager)
|
||||
IPrivilegeManager privilegeManager,
|
||||
IConfigurationManager configurationManager)
|
||||
{
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.screenshotProvider = screenshotProvider.ThrowIfNull(nameof(screenshotProvider));
|
||||
this.bloogumClient = bloogumClient.ThrowIfNull(nameof(bloogumClient));
|
||||
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
|
||||
this.privilegeManager = privilegeManager.ThrowIfNull(nameof(privilegeManager));
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.InitializeComponent();
|
||||
this.CurrentVersionText = this.applicationUpdater.CurrentVersion;
|
||||
this.LoadConfiguration();
|
||||
this.configurationManager.ConfigurationChanged += (s, e) => this.LoadConfiguration();
|
||||
this.CurrentVersionText = this.applicationUpdater.CurrentVersion.ToString();
|
||||
this.IsRunningAsAdmin = this.privilegeManager.AdminPrivileges;
|
||||
}
|
||||
|
||||
private void LoadConfiguration()
|
||||
{
|
||||
var configuration = this.configurationManager.GetConfiguration();
|
||||
this.canCheckUpdate = configuration.AutoCheckUpdate;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.SetupImageCycle();
|
||||
@@ -139,6 +153,11 @@ namespace Daybreak.Launch
|
||||
}
|
||||
}
|
||||
|
||||
private void VersionText_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<VersionManagementView>();
|
||||
}
|
||||
|
||||
private void SetImage(ImageSource imageSource)
|
||||
{
|
||||
this.ImageViewer.ShowImage(imageSource);
|
||||
@@ -159,7 +178,7 @@ namespace Daybreak.Launch
|
||||
|
||||
private async void CheckForUpdates()
|
||||
{
|
||||
var updateAvailable = await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
|
||||
var updateAvailable = this.canCheckUpdate is true && await this.applicationUpdater.UpdateAvailable().ConfigureAwait(true);
|
||||
if (updateAvailable)
|
||||
{
|
||||
this.viewManager.ShowView<AskUpdateView>();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Daybreak.Models.Github
|
||||
{
|
||||
public sealed class GithubRefTag
|
||||
{
|
||||
[JsonProperty("ref")]
|
||||
public string Ref;
|
||||
[JsonProperty("node_id")]
|
||||
public string NodeId;
|
||||
[JsonProperty("url")]
|
||||
public string Url;
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,11 @@ namespace Daybreak.Models
|
||||
public sealed class UpdateStatus : INotifyPropertyChanged
|
||||
{
|
||||
public static readonly UpdateStep StartingStep = new("Starting");
|
||||
public static readonly UpdateStep InitializingDownload = new("Initializing download");
|
||||
public static readonly UpdateStep CheckingLatestVersion = new("Checking latest version");
|
||||
public static UpdateStep Downloading(double progress) => new DownloadUpdateStep("Downloading", progress);
|
||||
public static readonly UpdateStep DownloadFinished = new("Download finished. Application will restart in order to apply the update.");
|
||||
public static readonly UpdateStep DownloadFinished = new("Download finished. Application will restart in order to apply the update");
|
||||
public static readonly UpdateStep FailedDownload = new("Update failed. Please check logs for details");
|
||||
|
||||
private UpdateStep currentStep = StartingStep;
|
||||
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Versioning
|
||||
{
|
||||
public sealed class Version
|
||||
{
|
||||
private List<VersionToken> parts = new();
|
||||
|
||||
public bool HasPrefix { get; private set; }
|
||||
public IEnumerable<VersionToken> VersionTokens { get => this.parts; }
|
||||
public string VersionString { get => this.ToString(); }
|
||||
|
||||
private Version()
|
||||
{
|
||||
}
|
||||
|
||||
public Version(string version)
|
||||
{
|
||||
if (TryParseParts(version, out var parts, out var hasPrefix) is false)
|
||||
{
|
||||
throw new ArgumentException($"Provided argument is not valid: {version}");
|
||||
}
|
||||
|
||||
this.parts = parts;
|
||||
this.HasPrefix = hasPrefix;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var version = string.Join('.', parts.OfType<VersionNumberToken>());
|
||||
if (parts.Last() is VersionStringToken)
|
||||
{
|
||||
version += "-" + parts.Last();
|
||||
}
|
||||
|
||||
if (this.HasPrefix)
|
||||
{
|
||||
version = 'v' + version;
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
|
||||
public static Version Parse(string version)
|
||||
{
|
||||
if (TryParse(version, out var parsedVersion) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Unable to parse version: {version}");
|
||||
}
|
||||
|
||||
return parsedVersion;
|
||||
}
|
||||
|
||||
public static bool TryParse(string version, out Version parsedVersion)
|
||||
{
|
||||
if (TryParseParts(version, out var parts, out var hasPrefix) is false)
|
||||
{
|
||||
parsedVersion = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = parts.Count - 1; i >= 1; i--)
|
||||
{
|
||||
if (parts[i] is VersionNumberToken && parts[i].ToString() == "0")
|
||||
{
|
||||
parts.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
parsedVersion = new Version
|
||||
{
|
||||
parts = parts,
|
||||
HasPrefix = hasPrefix
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool TryParseParts(string version, out List<VersionToken> parts, out bool hasPrefix)
|
||||
{
|
||||
hasPrefix = false;
|
||||
parts = null;
|
||||
if (version.IsNullOrWhiteSpace())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version.StartsWith('.') || version.EndsWith('.'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var tokens = version.Trim().Split('.');
|
||||
if (tokens.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tokens[0].StartsWith('v'))
|
||||
{
|
||||
hasPrefix = true;
|
||||
tokens[0] = tokens[0][1..];
|
||||
}
|
||||
|
||||
parts = new List<VersionToken>();
|
||||
for(int i = 0; i < tokens.Length - 1; i++)
|
||||
{
|
||||
var token = tokens[i];
|
||||
if (token.IsNullOrWhiteSpace() || token.All(c => char.IsDigit(c)) is false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
parts.Add(VersionToken.Parse(token));
|
||||
}
|
||||
|
||||
var lastToken = tokens[^1];
|
||||
if (lastToken.Contains('-'))
|
||||
{
|
||||
var lastTokenParts = lastToken.Split('-');
|
||||
if (lastTokenParts.Length > 2 || lastTokenParts.Length < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastTokenParts[0].IsNullOrWhiteSpace() || lastTokenParts[0].All(c => char.IsDigit(c)) is false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
parts.Add(VersionToken.Parse(lastTokenParts[0]));
|
||||
if (lastTokenParts[1].IsNullOrWhiteSpace() || lastTokenParts[1].All(c => char.IsLetter(c)) is false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
parts.Add(VersionToken.Parse(lastTokenParts[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lastToken.IsNullOrWhiteSpace() || lastToken.Any(c => char.IsDigit(c) is false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
parts.Add(VersionToken.Parse(lastToken));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Daybreak.Models.Versioning
|
||||
{
|
||||
public sealed class VersionNumberToken : VersionToken
|
||||
{
|
||||
public int Number { get; }
|
||||
internal VersionNumberToken(int number)
|
||||
{
|
||||
this.Number = number;
|
||||
}
|
||||
|
||||
protected override string Stringify()
|
||||
{
|
||||
return this.Number.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Daybreak.Models.Versioning
|
||||
{
|
||||
public sealed class VersionStringToken : VersionToken
|
||||
{
|
||||
public string Token { get; }
|
||||
internal VersionStringToken(string token)
|
||||
{
|
||||
this.Token = token;
|
||||
}
|
||||
|
||||
protected override string Stringify()
|
||||
{
|
||||
return this.Token;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Daybreak.Models.Versioning
|
||||
{
|
||||
public abstract class VersionToken
|
||||
{
|
||||
public static VersionToken Parse(string token)
|
||||
{
|
||||
if (token.All(c => char.IsDigit(c)))
|
||||
{
|
||||
var number = int.Parse(token);
|
||||
return new VersionNumberToken(number);
|
||||
}
|
||||
|
||||
if (token.All(c => char.IsLetter(c)))
|
||||
{
|
||||
return new VersionStringToken(token);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Failed to parse version token {token}");
|
||||
}
|
||||
|
||||
protected abstract string Stringify();
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Stringify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Exceptions;
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Models.Github;
|
||||
using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Runtime;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
@@ -16,6 +18,7 @@ using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Version = Daybreak.Models.Versioning.Version;
|
||||
|
||||
namespace Daybreak.Services.Updater
|
||||
{
|
||||
@@ -35,8 +38,10 @@ namespace Daybreak.Services.Updater
|
||||
private const string ProcessIdTag = "{PROCESSID}";
|
||||
private const string ExecutableNameTag = "{EXECUTABLE}";
|
||||
private const string WorkingDirectoryTag = "{WORKINGDIRECTORY}";
|
||||
private const string RefTagPrefix = "/refs/tags";
|
||||
private const string VersionListUrl = "https://api.github.com/repos/AlexMacocian/Daybreak/git/refs/tags";
|
||||
private const string Url = "https://github.com/AlexMacocian/Daybreak/releases/latest";
|
||||
private const string DownloadUrl = $"https://github.com/AlexMacocian/Daybreak/releases/download/v{VersionTag}/Daybreakv{VersionTag}.zip";
|
||||
private const string DownloadUrl = $"https://github.com/AlexMacocian/Daybreak/releases/download/{VersionTag}/Daybreak{VersionTag}.zip";
|
||||
private const string GetExecutionPolicyCommand = "Get-ExecutionPolicy -Scope CurrentUser";
|
||||
private const string SetExecutionPolicyCommand = $"Set-ExecutionPolicy {ExecutionPolicyTag} -Scope CurrentUser";
|
||||
private const string WaitCommand = $"Wait-Process -Id {ProcessIdTag}";
|
||||
@@ -56,7 +61,7 @@ namespace Daybreak.Services.Updater
|
||||
private readonly IRuntimeStore runtimeStore;
|
||||
private readonly HttpClient httpClient = new();
|
||||
|
||||
public string CurrentVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
public Version CurrentVersion { get; }
|
||||
|
||||
public ApplicationUpdater(
|
||||
ILogger logger,
|
||||
@@ -66,31 +71,38 @@ namespace Daybreak.Services.Updater
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.httpClient.DefaultRequestHeaders.Add("user-agent", "Daybreak Client");
|
||||
if (Version.TryParse(Assembly.GetExecutingAssembly().GetName().Version.ToString(), out var currentVersion))
|
||||
{
|
||||
if (currentVersion.HasPrefix is false)
|
||||
{
|
||||
currentVersion = Version.Parse("v" + currentVersion);
|
||||
}
|
||||
|
||||
this.CurrentVersion = currentVersion;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FatalException($"Application version is invalid: {Assembly.GetExecutingAssembly().GetName().Version}");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DownloadUpdate(UpdateStatus updateStatus)
|
||||
public async Task<bool> DownloadUpdate(Version version, UpdateStatus updateStatus)
|
||||
{
|
||||
updateStatus.CurrentStep = UpdateStatus.CheckingLatestVersion;
|
||||
var latestVersion = (await this.GetLatestVersion()).ExtractValue();
|
||||
if (latestVersion is null)
|
||||
updateStatus.CurrentStep = UpdateStatus.InitializingDownload;
|
||||
var uri = DownloadUrl.Replace(VersionTag, version.ToString());
|
||||
using var response = await this.httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
|
||||
if (response.IsSuccessStatusCode is false)
|
||||
{
|
||||
this.logger.LogWarning("Failed to retrieve latest version. Aborting update");
|
||||
return false;
|
||||
}
|
||||
|
||||
using var downloadLatestResponse = await this.httpClient.GetAsync(
|
||||
DownloadUrl.Replace(VersionTag, latestVersion));
|
||||
|
||||
if (downloadLatestResponse.IsSuccessStatusCode is false)
|
||||
{
|
||||
this.logger.LogWarning("Failed to download latest version. Aborting udpate");
|
||||
updateStatus.CurrentStep = UpdateStatus.FailedDownload;
|
||||
this.logger.LogError($"Failed to download update. Details: {await response.Content.ReadAsStringAsync()}");
|
||||
return false;
|
||||
}
|
||||
|
||||
using var downloadStream = await this.httpClient.GetStreamAsync(uri);
|
||||
this.logger.LogInformation("Beginning update download");
|
||||
var downloadStream = await downloadLatestResponse.Content.ReadAsStreamAsync();
|
||||
var fileStream = File.OpenWrite(TempFile);
|
||||
var downloadSize = (double)downloadStream.Length;
|
||||
var downloadSize = (double)response.Content.Headers.ContentLength;
|
||||
var buffer = new byte[1024];
|
||||
var length = 0;
|
||||
double downloaded = 0;
|
||||
@@ -113,12 +125,29 @@ namespace Daybreak.Services.Updater
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> DownloadLatestUpdate(UpdateStatus updateStatus)
|
||||
{
|
||||
updateStatus.CurrentStep = UpdateStatus.CheckingLatestVersion;
|
||||
var latestVersion = (await this.GetLatestVersion()).ExtractValue();
|
||||
if (latestVersion is null)
|
||||
{
|
||||
this.logger.LogWarning("Failed to retrieve latest version. Aborting update");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Version.TryParse(latestVersion, out var parsedVersion) is false)
|
||||
{
|
||||
throw new InvalidOperationException($"Could not parse retrieved version: {latestVersion}");
|
||||
}
|
||||
|
||||
return await this.DownloadUpdate(parsedVersion, updateStatus);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAvailable()
|
||||
{
|
||||
var version = string.Join('.', this.CurrentVersion.Split('.'));
|
||||
var maybeLatestVersion = await this.GetLatestVersion();
|
||||
return maybeLatestVersion.Switch(
|
||||
onSome: latestVersion => string.Compare(version, latestVersion, true) < 0,
|
||||
onSome: latestVersion => string.Compare(this.CurrentVersion.ToString().Trim('v'), latestVersion, true) < 0,
|
||||
onNone: () =>
|
||||
{
|
||||
this.logger.LogWarning("Failed to retrieve latest version");
|
||||
@@ -126,6 +155,20 @@ namespace Daybreak.Services.Updater
|
||||
}).ExtractValue();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Version>> GetVersions()
|
||||
{
|
||||
this.logger.LogInformation($"Retrieving version list from {VersionListUrl}");
|
||||
var response = await this.httpClient.GetAsync(VersionListUrl);
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var serializedList = await response.Content.ReadAsStringAsync();
|
||||
var versionList = serializedList.Deserialize<GithubRefTag[]>();
|
||||
return versionList.Select(v => v.Ref.Remove(0, RefTagPrefix.Length)).Select(v => new Version(v));
|
||||
}
|
||||
|
||||
return new List<Version>();
|
||||
}
|
||||
|
||||
public void PeriodicallyCheckForUpdates()
|
||||
{
|
||||
System.Extensions.TaskExtensions.RunPeriodicAsync(async () =>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
using Daybreak.Models;
|
||||
using Daybreak.Models.Versioning;
|
||||
using Daybreak.Services.ApplicationLifetime;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Daybreak.Services.Updater
|
||||
{
|
||||
public interface IApplicationUpdater : IApplicationLifetimeService
|
||||
{
|
||||
string CurrentVersion { get; }
|
||||
Version CurrentVersion { get; }
|
||||
void FinalizeUpdate();
|
||||
void PeriodicallyCheckForUpdates();
|
||||
Task<IEnumerable<Version>> GetVersions();
|
||||
Task<bool> UpdateAvailable();
|
||||
Task<bool> DownloadUpdate(UpdateStatus updateStatus);
|
||||
Task<bool> DownloadUpdate(Version version, UpdateStatus updateStatus);
|
||||
Task<bool> DownloadLatestUpdate(UpdateStatus updateStatus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Utils;
|
||||
using System.Extensions;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Daybreak.Views
|
||||
@@ -20,17 +21,20 @@ namespace Daybreak.Views
|
||||
private readonly IViewManager viewManager;
|
||||
private readonly IRuntimeStore runtimeStore;
|
||||
private readonly IPrivilegeManager privilegeManager;
|
||||
private readonly IApplicationUpdater applicationUpdater;
|
||||
|
||||
public AskUpdateView(
|
||||
ILogger logger,
|
||||
IViewManager viewManager,
|
||||
IRuntimeStore runtimeStore,
|
||||
IPrivilegeManager privilegeManager)
|
||||
IPrivilegeManager privilegeManager,
|
||||
IApplicationUpdater applicationUpdater)
|
||||
{
|
||||
this.logger = logger.ThrowIfNull(nameof(logger));
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.runtimeStore = runtimeStore.ThrowIfNull(nameof(runtimeStore));
|
||||
this.privilegeManager = privilegeManager.ThrowIfNull(nameof(privilegeManager));
|
||||
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
@@ -52,7 +56,7 @@ namespace Daybreak.Views
|
||||
this.viewManager.ShowView<MainView>();
|
||||
}
|
||||
|
||||
private void YesButton_Clicked(object sender, System.EventArgs e)
|
||||
private async void YesButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.logger.LogInformation("User accepted update");
|
||||
this.runtimeStore.StoreValue(UpdateDesiredKey, true);
|
||||
@@ -61,7 +65,8 @@ namespace Daybreak.Views
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewManager.ShowView<UpdateView>();
|
||||
var latestVersion = (await this.applicationUpdater.GetVersions()).Last();
|
||||
this.viewManager.ShowView<UpdateView>(latestVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,12 @@
|
||||
<controls:FireballGlyph></controls:FireballGlyph>
|
||||
</controls:TileButton.InnerContent>
|
||||
</controls:TileButton>
|
||||
<controls:TileButton Title="Version management" Foreground="White" BorderBrush="White" BorderThickness="2"
|
||||
HighlightColor="White" Clicked="VersionButton_Clicked" Height="150" Width="150">
|
||||
<controls:TileButton.InnerContent>
|
||||
<controls:StaticGlyph></controls:StaticGlyph>
|
||||
</controls:TileButton.InnerContent>
|
||||
</controls:TileButton>
|
||||
</WrapPanel>
|
||||
</WrapPanel>
|
||||
</Grid>
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace Daybreak.Views
|
||||
this.viewManager.ShowView<BuildsListView>();
|
||||
}
|
||||
|
||||
private void VersionButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<VersionManagementView>(this);
|
||||
}
|
||||
|
||||
private void FileButton_Clicked(object sender, System.EventArgs e)
|
||||
{
|
||||
this.viewManager.ShowView<ExecutablesView>();
|
||||
|
||||
@@ -82,7 +82,8 @@
|
||||
<controls:SaveButton Foreground="White" Height="30" Width="30" Grid.Column="1" HorizontalAlignment="Right" Margin="5"
|
||||
Clicked="SaveButton_Clicked"></controls:SaveButton>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1">
|
||||
<TextBlock Text="Texmod path" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Auto check for updates: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Texmod path: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox auto-launch: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="GWToolbox path: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Browsers enabled: " FontSize="22" Foreground="White" Height="30"/>
|
||||
@@ -91,10 +92,12 @@
|
||||
<TextBlock Text="Right browser homepage: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Auto-place on desired screen: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Desired screen id: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Place Shortcut" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Shortcut folder" FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Place Shortcut: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
<TextBlock Text="Shortcut folder: " FontSize="22" Foreground="White" Height="30"></TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" Grid.Row="1" Grid.Column="1">
|
||||
<ToggleButton HorizontalAlignment="Center" HorizontalContentAlignment="Stretch" Style="{StaticResource AnimatedSwitch}" Height="30" Width="40"
|
||||
FontSize="22" Foreground="White" IsChecked="{Binding ElementName=_this, Path=AutoCheckUpdate, Mode=TwoWay}"></ToggleButton>
|
||||
<Grid Height="30">
|
||||
<TextBox HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
|
||||
FontSize="22" Margin="0, 0, 30, 0" Background="Transparent" Foreground="White"
|
||||
|
||||
@@ -43,11 +43,12 @@ namespace Daybreak.Views
|
||||
private string shortcutFolder;
|
||||
[GenerateDependencyProperty]
|
||||
private bool shortcutPlaced;
|
||||
[GenerateDependencyProperty]
|
||||
private bool autoCheckUpdate;
|
||||
|
||||
public SettingsView(
|
||||
IConfigurationManager configurationManager,
|
||||
IViewManager viewManager,
|
||||
IShortcutManager shortcutManager)
|
||||
IViewManager viewManager)
|
||||
{
|
||||
this.configurationManager = configurationManager.ThrowIfNull(nameof(configurationManager));
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
@@ -69,7 +70,7 @@ namespace Daybreak.Views
|
||||
this.DesiredScreen = config.DesiredGuildwarsScreen.ToString();
|
||||
this.ShortcutFolder = config.ShortcutLocation;
|
||||
this.ShortcutPlaced = config.PlaceShortcut;
|
||||
|
||||
this.AutoCheckUpdate = config.AutoCheckUpdate;
|
||||
}
|
||||
|
||||
private void SaveButton_Clicked(object sender, EventArgs e)
|
||||
@@ -86,6 +87,7 @@ namespace Daybreak.Views
|
||||
currentConfig.DesiredGuildwarsScreen = int.Parse(this.DesiredScreen);
|
||||
currentConfig.ShortcutLocation = this.ShortcutFolder;
|
||||
currentConfig.PlaceShortcut = this.ShortcutPlaced;
|
||||
currentConfig.AutoCheckUpdate = this.AutoCheckUpdate;
|
||||
this.configurationManager.SaveConfiguration(currentConfig);
|
||||
this.viewManager.ShowView<SettingsCategoryView>();
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ using Daybreak.Services.Logging;
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using Daybreak.Utils;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using Version = Daybreak.Models.Versioning.Version;
|
||||
|
||||
namespace Daybreak.Views
|
||||
{
|
||||
@@ -56,8 +58,14 @@ namespace Daybreak.Views
|
||||
|
||||
private async void UpdateView_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (this.DataContext is not Version version)
|
||||
{
|
||||
this.viewManager.ShowView<MainView>();
|
||||
throw new InvalidOperationException("No version specified for download");
|
||||
}
|
||||
|
||||
this.logger.LogInformation("Starting update procedure");
|
||||
var success = await applicationUpdater.DownloadUpdate(updateStatus).ConfigureAwait(true);
|
||||
var success = await applicationUpdater.DownloadUpdate(version, updateStatus).ConfigureAwait(true);
|
||||
if (success is false)
|
||||
{
|
||||
this.logger.LogError("Update procedure failed");
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<UserControl x:Class="Daybreak.Views.VersionManagementView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Daybreak.Views"
|
||||
xmlns:controls="clr-namespace:Daybreak.Controls"
|
||||
mc:Ignorable="d"
|
||||
x:Name="_this"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid Background="#A0202020">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="auto"></RowDefinition>
|
||||
<RowDefinition Height="*"></RowDefinition>
|
||||
</Grid.RowDefinitions>
|
||||
<controls:BackButton Foreground="White" Height="30" Width="30" Grid.Column="0" HorizontalAlignment="Left" Margin="5"
|
||||
Clicked="BackButton_Clicked"></controls:BackButton>
|
||||
<TextBlock Text="Manage application version" FontSize="18" Foreground="White" HorizontalAlignment="Center"></TextBlock>
|
||||
<WrapPanel Grid.Row="1" HorizontalAlignment="Center" Margin="10">
|
||||
<TextBlock Text="Current version: " Foreground="White" FontSize="16"></TextBlock>
|
||||
<controls:OpaqueButton Text="{Binding ElementName=_this, Path=CurrentVersion.VersionString, Mode=OneWay}" Foreground="White" FontSize="16"
|
||||
Cursor="Hand" BorderBrush="Transparent" BorderThickness="0" Clicked="CurrentVersion_Clicked"></controls:OpaqueButton>
|
||||
</WrapPanel>
|
||||
<ListView Grid.Row="2"
|
||||
Background="Transparent" ItemsSource="{Binding ElementName=_this, Path=Versions, Mode=OneWay}"
|
||||
HorizontalContentAlignment="Stretch" Width="230" ScrollViewer.CanContentScroll="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="5">
|
||||
<controls:OpaqueButton Text="{Binding VersionString}" Clicked="DesiredVersion_Clicked"
|
||||
Foreground="White" FontSize="16" BorderThickness="0"
|
||||
HorizontalAlignment="Left"></controls:OpaqueButton>
|
||||
<controls:BackButton Foreground="White" Width="30" Height="30" HorizontalAlignment="Right"
|
||||
Clicked="DesiredVersion_DownloadButton_Clicked">
|
||||
<controls:BackButton.RenderTransform>
|
||||
<RotateTransform Angle="270" CenterX="15" CenterY="15"></RotateTransform>
|
||||
</controls:BackButton.RenderTransform>
|
||||
</controls:BackButton>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,92 @@
|
||||
using Daybreak.Services.Updater;
|
||||
using Daybreak.Services.ViewManagement;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Extensions;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Extensions;
|
||||
using Version = Daybreak.Models.Versioning.Version;
|
||||
|
||||
namespace Daybreak.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for VersionManagementView.xaml
|
||||
/// </summary>
|
||||
public partial class VersionManagementView : UserControl
|
||||
{
|
||||
private const string VersionPlaceholder = "{VERSION}";
|
||||
private const string ReleaseURL = $"https://github.com/AlexMacocian/Daybreak/releases/tag/{VersionPlaceholder}";
|
||||
|
||||
private readonly IApplicationUpdater applicationUpdater;
|
||||
private readonly IViewManager viewManager;
|
||||
|
||||
[GenerateDependencyProperty]
|
||||
private Version currentVersion;
|
||||
|
||||
public ObservableCollection<Version> Versions { get; } = new();
|
||||
|
||||
public VersionManagementView(
|
||||
IApplicationUpdater applicationUpdater,
|
||||
IViewManager viewManager)
|
||||
{
|
||||
this.applicationUpdater = applicationUpdater.ThrowIfNull(nameof(applicationUpdater));
|
||||
this.viewManager = viewManager.ThrowIfNull(nameof(viewManager));
|
||||
this.InitializeComponent();
|
||||
this.CurrentVersion = this.applicationUpdater.CurrentVersion;
|
||||
this.LoadVersionList();
|
||||
}
|
||||
|
||||
private async void LoadVersionList()
|
||||
{
|
||||
this.Versions.ClearAnd().AddRange(await this.applicationUpdater.GetVersions());
|
||||
}
|
||||
|
||||
private void CurrentVersion_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
Process.Start("explorer.exe", ReleaseURL.Replace(VersionPlaceholder, this.currentVersion.ToString()));
|
||||
}
|
||||
|
||||
private void DesiredVersion_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is not UserControl userControl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (userControl.DataContext is not Version desiredVersion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Process.Start("explorer.exe", ReleaseURL.Replace(VersionPlaceholder, desiredVersion.ToString()));
|
||||
}
|
||||
|
||||
private void DesiredVersion_DownloadButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is not UserControl userControl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (userControl.DataContext is not Version desiredVersion)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewManager.ShowView<UpdateView>(desiredVersion);
|
||||
}
|
||||
|
||||
private void BackButton_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (this.DataContext is UserControl userControl)
|
||||
{
|
||||
this.viewManager.ShowView(userControl.GetType());
|
||||
}
|
||||
else
|
||||
{
|
||||
this.viewManager.ShowView<MainView>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user