Skip to content

Commit

Permalink
Add VersionAvailable popup dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
0blu committed Nov 19, 2023
1 parent 9c30dbf commit 97c8c47
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 0 deletions.
17 changes: 17 additions & 0 deletions WinterspringLauncher/LauncherLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Threading;
using WinterspringLauncher.Utils;
using WinterspringLauncher.ViewModels;
using WinterspringLauncher.Views;

namespace WinterspringLauncher;

Expand Down Expand Up @@ -76,6 +80,7 @@ public LauncherLogic(MainWindowViewModel model)
_model.AddLogEntry($"This launcher has a new version {updateInformation.VersionName} ({updateInformation.ReleaseDate:yyyy-MM-dd})");
_model.AddLogEntry($"You can download it here {updateInformation.URLLinkToReleasePage}");
_model.AddLogEntry($"--------------------------");
CreateUpdatePopup(updateInformation);
}
Console.WriteLine("Launcher update check done");
}
Expand All @@ -88,6 +93,18 @@ public LauncherLogic(MainWindowViewModel model)
}
}

private void CreateUpdatePopup(LauncherVersion.UpdateInformation updateInformation)
{
Dispatcher.UIThread.Post(() =>
{
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop.MainWindow != null)
{
var dialog = new NewVersionAvailableDialog(updateInformation);
dialog.ShowDialog(desktop.MainWindow);
}
});
}

public void ChangeServerIdx()
{
var serverInfo = _config.KnownServers.ElementAtOrDefault(_model.SelectedServerIdx);
Expand Down
93 changes: 93 additions & 0 deletions WinterspringLauncher/LauncherUpdateHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;

namespace WinterspringLauncher;

public static class LauncherUpdateHandler
{
public static bool/*exitNow*/ HandleStartArguments(string[] args)
{
if (args.Length != 2)
return false;

var actionName = args[0];
var targetPath = args[1];
if (string.IsNullOrWhiteSpace(targetPath))
{
Console.WriteLine("AutoUpdate: Target path is empty");
return true;
}

switch (actionName)
{
case "--copy-self-to":
{
CreateTerminalWindowIfPossible();
Console.WriteLine($"Updating launcher '{targetPath}'");
var ourPath = Process.GetCurrentProcess().MainModule!.FileName!;
bool wasSuccessful = false;
const int maxTries = 20;
for (int i = 0; i < maxTries; i++)
{
try
{
File.Copy(ourPath, targetPath, overwrite: true);
wasSuccessful = true;
}
catch(IOException)
{
Console.WriteLine($"Need to wait for old process to close (this might take a bit) (try {i + 1}/{maxTries})");
Thread.Sleep(TimeSpan.FromMilliseconds(500));
}
}

if (!wasSuccessful)
{
Console.WriteLine("Update was not successful, please try again or update manually");
Thread.Sleep(TimeSpan.FromSeconds(10));
return true;
}

Console.WriteLine("Start new launcher");
Process.Start(new ProcessStartInfo{
FileName = targetPath,
Arguments = $"--delete-tmp-updater-file \"{ourPath}\"",
UseShellExecute = true,
});
return true;
}
case "--delete-tmp-updater-file":
{
Thread.Sleep(TimeSpan.FromMilliseconds(500));
try
{
Console.WriteLine($"Removing tmp file '{targetPath}'");
File.Delete(targetPath);
}
catch
{
// Ignore
}
return false; // keep our current instance
}
default:
return false;
}
}

#if PLATFORM_WINDOWS
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
#endif

private static void CreateTerminalWindowIfPossible()
{
#if PLATFORM_WINDOWS
AttachConsole(ATTACH_PARENT_PROCESS);
#endif
}
}
3 changes: 3 additions & 0 deletions WinterspringLauncher/ProgramStartup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ public static void Main(string[] args)
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

if (LauncherUpdateHandler.HandleStartArguments(args))
return;

if (args.Contains("--use-asia-defaults"))
LocaleDefaults.ShouldUseAsiaPreferences = true;

Expand Down
40 changes: 40 additions & 0 deletions WinterspringLauncher/UiElements/HyperlinkSpan.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Media;

namespace WinterspringLauncher.UiElements;

public class HyperlinkTextBlock : TextBlock
{
public static readonly DirectProperty<HyperlinkTextBlock, string> NavigateUriProperty =
AvaloniaProperty.RegisterDirect<HyperlinkTextBlock, string>(
nameof(NavigateUri),
o => o.NavigateUri,
(o, v) => o.NavigateUri = v);

private string _navigateUri;

public string NavigateUri
{
get => _navigateUri;
set => SetAndRaise(NavigateUriProperty, ref _navigateUri, value);
}

public HyperlinkTextBlock()
{
AddHandler(PointerPressedEvent, OnPointerPressed);
PseudoClasses.Add(":pointerover");
Cursor = new Cursor(StandardCursorType.Hand);
Foreground = Brush.Parse("#2E95D3");
}

private void OnPointerPressed(object sender, PointerPressedEventArgs e)
{
if (!string.IsNullOrEmpty(NavigateUri))
{
// Open the link here, for example, by launching a browser
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(NavigateUri) { UseShellExecute = true });
}
}
}
1 change: 1 addition & 0 deletions WinterspringLauncher/Views/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using WinterspringLauncher.ViewModels;
Expand Down
28 changes: 28 additions & 0 deletions WinterspringLauncher/Views/NewVersionAvailableDialog.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uiElements="clr-namespace:WinterspringLauncher.UiElements"
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="100"
x:Class="WinterspringLauncher.Views.NewVersionAvailableDialog"
Title="WinterspringLauncher Update Available!"
Width="450" Height="120"
MinWidth="450" MinHeight="120"
CanResize="False"
WindowStartupLocation="CenterScreen">

<Grid RowDefinitions="*, Auto" ColumnDefinitions="*">
<StackPanel Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock FontSize="20" Text="Update available!"/>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="15" Text="Version: " />
<TextBlock x:Name="VersionIndicator" FontSize="15" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Download: " />
<uiElements:HyperlinkTextBlock x:Name="DlLinkIndicator" NavigateUri="https://github.com/0blu/WinterspringLauncher" Text="https://github.com/0blu/WinterspringLauncher" />
</StackPanel>
</StackPanel>
<Button Grid.Row="1" Click="CloseButtonClick">Close</Button>
</Grid>
</Window>
37 changes: 37 additions & 0 deletions WinterspringLauncher/Views/NewVersionAvailableDialog.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using WinterspringLauncher.UiElements;

namespace WinterspringLauncher.Views;

public partial class NewVersionAvailableDialog : Window
{
public string NewVersion { get; set; }

public NewVersionAvailableDialog(LauncherVersion.UpdateInformation updateInformation)

Check warning on line 13 in WinterspringLauncher/Views/NewVersionAvailableDialog.axaml.cs

View workflow job for this annotation

GitHub Actions / build_macos (macos)

Non-nullable property 'NewVersion' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 13 in WinterspringLauncher/Views/NewVersionAvailableDialog.axaml.cs

View workflow job for this annotation

GitHub Actions / build_windows (windows)

Non-nullable property 'NewVersion' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif

TextBlock version = this.Find<TextBlock>("VersionIndicator")!;
HyperlinkTextBlock dlLinkIndicator = this.Find<HyperlinkTextBlock>("DlLinkIndicator")!;

version.Text = updateInformation.VersionName;
dlLinkIndicator.NavigateUri = updateInformation.URLLinkToReleasePage;
dlLinkIndicator.Text = updateInformation.URLLinkToReleasePage;
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}

private void CloseButtonClick(object? sender, RoutedEventArgs e)
{
Close();
}
}

0 comments on commit 97c8c47

Please sign in to comment.