From ac787d19766ed710fe127dac7b6f23e3dce01b80 Mon Sep 17 00:00:00 2001 From: Tomi Eckert Date: Tue, 16 Dec 2025 06:03:32 +0100 Subject: [PATCH] add update button --- Blueberry/App.xaml.cs | 8 ++++++- Blueberry/Constants.cs | 34 +++++++++++++++++++++++++++++- Blueberry/MainWindow.xaml | 3 +-- Blueberry/MainWindow.xaml.cs | 9 ++++++-- Blueberry/UpdateManager.cs | 41 ++++++++++++++++++++++++++++++++++-- 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/Blueberry/App.xaml.cs b/Blueberry/App.xaml.cs index b85f6a9..aacffcd 100644 --- a/Blueberry/App.xaml.cs +++ b/Blueberry/App.xaml.cs @@ -1,4 +1,5 @@ -using Blueberry.Redmine; +using Blueberry; +using Blueberry.Redmine; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -65,6 +66,11 @@ namespace BlueMine await _host.StopAsync(); _host.Dispose(); + + if (await UpdateManager.IsUpdateAvailable()) + { + await UpdateManager.WaitUntilDownloadCompleteAndUpdate(); + } } /// diff --git a/Blueberry/Constants.cs b/Blueberry/Constants.cs index a2e6c3f..cfe2057 100644 --- a/Blueberry/Constants.cs +++ b/Blueberry/Constants.cs @@ -29,7 +29,7 @@ "Nem elszámolható telefon, chat, email kommunikáció", ]; - public static readonly string UpdateScript = @"# Wait for the main app to close completely + public static readonly string UpdateScriptRestart = @"# Wait for the main app to close completely Start-Sleep -Seconds 2 $exePath = '{currentExe}' @@ -62,6 +62,38 @@ Remove-Item $zipPath -Force # 'Start-Process' is the robust way to launch detached processes in PS Start-Process -FilePath $exePath -WorkingDirectory $destDir +# SELF-DESTRUCT: Remove this script +Remove-Item -LiteralPath $MyInvocation.MyCommand.Path -Force"; + + public static readonly string UpdateScriptNoRestart = @"# Wait for the main app to close completely +Start-Sleep -Seconds 2 + +$exePath = '{currentExe}' +$zipPath = '{tempZip}' +$destDir = '{appDir}' + +# Retry logic for deletion (in case antivirus or OS holds the lock) +$maxRetries = 10 +$retryCount = 0 + +while ($retryCount -lt $maxRetries) { + try { + # Attempt to delete the old executable + if (Test-Path $exePath) { Remove-Item $exePath -Force -ErrorAction Stop } + break # If successful, exit loop + } + catch { + Start-Sleep -Milliseconds 500 + $retryCount++ + } +} + +# Unzip the new version +Expand-Archive -Path $zipPath -DestinationPath $destDir -Force + +# CLEANUP: Delete the zip +Remove-Item $zipPath -Force + # SELF-DESTRUCT: Remove this script Remove-Item -LiteralPath $MyInvocation.MyCommand.Path -Force"; } diff --git a/Blueberry/MainWindow.xaml b/Blueberry/MainWindow.xaml index 1959f3c..9dc7fac 100644 --- a/Blueberry/MainWindow.xaml +++ b/Blueberry/MainWindow.xaml @@ -262,8 +262,7 @@ - + diff --git a/Blueberry/MainWindow.xaml.cs b/Blueberry/MainWindow.xaml.cs index 6066ad8..dc0d974 100644 --- a/Blueberry/MainWindow.xaml.cs +++ b/Blueberry/MainWindow.xaml.cs @@ -47,7 +47,7 @@ namespace BlueMine #if !DEBUG if(await UpdateManager.IsUpdateAvailable()) { - updateIcon.Visibility = Visibility.Visible; + updateButton.Visibility = Visibility.Visible; UpdateManager.DownloadCompleted += UpdateManager_DownloadCompleted; await UpdateManager.DownloadUpdateAsync(); } @@ -69,7 +69,7 @@ namespace BlueMine }.ShowDialogAsync(); if (result == Wpf.Ui.Controls.MessageBoxResult.Primary) - await UpdateManager.PerformUpdate(); + await UpdateManager.PerformUpdate(true); }); } @@ -373,6 +373,11 @@ namespace BlueMine Title = "Under construction" }.ShowDialogAsync(); } + + private void updateButton_Click(object sender, RoutedEventArgs e) + { + UpdateManager_DownloadCompleted(); + } } public partial class MainWindow : FluentWindow diff --git a/Blueberry/UpdateManager.cs b/Blueberry/UpdateManager.cs index 75bfed8..5bdcca7 100644 --- a/Blueberry/UpdateManager.cs +++ b/Blueberry/UpdateManager.cs @@ -23,6 +23,43 @@ namespace Blueberry return release != null && release.tag_name != CurrentVersion; } + public static async Task WaitUntilDownloadCompleteAndUpdate() + { + var json = await client.GetStringAsync(releaseUrl); + var release = JsonSerializer.Deserialize(json); + var file = release.assets.Find(x => x.name.Contains(".zip")); + if (!File.Exists(zipPath)) + await Download(client, file.browser_download_url, 0); + + long localSize = new FileInfo(zipPath).Length; + if (localSize != file.size) + { + if (!isDownloading) + { + await Download(client, file.browser_download_url, localSize); + if (localSize != file.size) + await PerformUpdate(); + } + else + { + do + { + await Task.Delay(500); + localSize = new FileInfo(zipPath).Length; + } while (localSize != file.size); + localSize = new FileInfo(zipPath).Length; + if (localSize != file.size) + await PerformUpdate(); + } + } + + localSize = new FileInfo(zipPath).Length; + if (localSize != file.size) + return; + else + await PerformUpdate(); + } + public static async Task DownloadUpdateAsync() { client.DefaultRequestHeaders.Add("User-Agent", "Blueberry-Updater"); @@ -103,11 +140,11 @@ namespace Blueberry } } - public static async Task PerformUpdate() + public static async Task PerformUpdate(bool restart = false) { string currentExe = Process.GetCurrentProcess().MainModule.FileName; - string psScript = Constants.UpdateScript + string psScript = (restart ? Constants.UpdateScriptRestart : Constants.UpdateScriptNoRestart) .Replace("{currentExe}", $"{currentExe}") .Replace("{tempZip}", $"{zipPath}") .Replace("{appDir}", $"{appDir}");