Skip to content

Commit 264edee

Browse files
authored
Merge pull request #523 from memstechtips/dev
Release v26.03.11
2 parents 4923eb3 + f1090d3 commit 264edee

35 files changed

Lines changed: 252 additions & 41 deletions

File tree

extras/Winhance.Installer.iss

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ SetupIconFile=C:\Winhance\src\Winhance.UI\Assets\AppIcons\winhance-rocket.ico
4646
VersionInfoCopyright=Copyright © Marco du Plessis
4747
SolidCompression=yes
4848
WizardStyle=modern
49-
; Allow user to select installation type
50-
DisableDirPage=no
49+
; Dir page is replaced by a custom page that appears after task selection
50+
DisableDirPage=yes
5151
; Only create uninstaller for regular installations
5252
Uninstallable=WizardIsTaskSelected('regularinstall')
5353
; Close applications before installation/uninstallation
@@ -132,14 +132,21 @@ begin
132132
end;
133133
134134
var
135-
UserSelectedDir: String;
136-
IsFirstRun: Boolean;
135+
CustomDirPage: TInputDirWizardPage;
136+
HasSetDefaultDir: Boolean;
137137
138138
procedure InitializeWizard;
139139
begin
140-
// Initialize variables
141-
IsFirstRun := True;
142-
UserSelectedDir := '';
140+
HasSetDefaultDir := False;
141+
142+
// Create a custom directory page that appears AFTER the tasks page
143+
CustomDirPage := CreateInputDirPage(wpSelectTasks,
144+
SetupMessage(msgWizardSelectDir),
145+
'',
146+
'To continue, click Next. If you would like to select a different folder, click Browse.',
147+
False, '');
148+
CustomDirPage.Add('');
149+
CustomDirPage.Values[0] := ExpandConstant('{autopf}\{#MyAppName}');
143150
end;
144151
145152
// This function runs right before the actual installation starts
@@ -154,30 +161,24 @@ end;
154161
function NextButtonClick(CurPageID: Integer): Boolean;
155162
begin
156163
Result := True;
157-
158-
// Save user-selected directory when leaving the directory selection page
159-
if CurPageID = wpSelectDir then
160-
begin
161-
UserSelectedDir := WizardForm.DirEdit.Text;
162-
end;
163-
164-
// Set default directory based on installation type when tasks page is shown for the first time
164+
165+
// After task selection, set the default directory based on installation type
165166
if CurPageID = wpSelectTasks then
166167
begin
167-
if IsFirstRun then
168+
if not HasSetDefaultDir then
168169
begin
169-
IsFirstRun := False;
170-
if WizardIsTaskSelected('portableinstall') and (UserSelectedDir = '') then
171-
WizardForm.DirEdit.Text := ExpandConstant('{userdesktop}\{#MyAppName}')
172-
else if WizardIsTaskSelected('regularinstall') and (UserSelectedDir = '') then
173-
WizardForm.DirEdit.Text := ExpandConstant('{autopf}\{#MyAppName}');
170+
HasSetDefaultDir := True;
171+
if WizardIsTaskSelected('portableinstall') then
172+
CustomDirPage.Values[0] := ExpandConstant('{userdesktop}\{#MyAppName}')
173+
else
174+
CustomDirPage.Values[0] := ExpandConstant('{autopf}\{#MyAppName}');
174175
end;
175176
end;
176-
177-
// Restore user's custom directory selection after task selection
178-
if (CurPageID = wpSelectTasks) and (UserSelectedDir <> '') then
177+
178+
// Sync the custom dir page value to the actual install directory
179+
if CurPageID = CustomDirPage.ID then
179180
begin
180-
WizardForm.DirEdit.Text := UserSelectedDir;
181+
WizardForm.DirEdit.Text := CustomDirPage.Values[0];
181182
end;
182183
end;
183184

src/Winhance.Core/Features/Common/Interfaces/IVersionService.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@ public interface IVersionService
1818
Task<VersionInfo> CheckForUpdateAsync(CancellationToken cancellationToken = default);
1919

2020
/// <summary>
21-
/// Downloads and launches the installer for the latest version
21+
/// Downloads the installer for the latest version to a temp location.
2222
/// </summary>
23-
/// <returns>A task that completes when the download is initiated</returns>
2423
Task DownloadAndInstallUpdateAsync(CancellationToken cancellationToken = default);
24+
25+
/// <summary>
26+
/// Launches the downloaded installer and schedules the app to relaunch after installation.
27+
/// The caller should exit the application immediately after calling this.
28+
/// </summary>
29+
void LaunchInstallerAndRestart();
2530
}

src/Winhance.Infrastructure/Features/Common/Services/VersionService.cs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class VersionService : IVersionService
2020
private readonly string _latestReleaseApiUrl = "https://api.github.com/repos/memstechtips/Winhance/releases/latest";
2121
private readonly string _latestReleaseDownloadUrl = "https://github.com/memstechtips/Winhance/releases/latest/download/Winhance.Installer.exe";
2222
private readonly string _userAgent = "Winhance-Update-Checker";
23+
private string? _downloadedInstallerPath;
2324

2425
public VersionService(ILogService logService, IProcessExecutor processExecutor, IFileSystemService fileSystemService, HttpClient httpClient)
2526
{
@@ -154,16 +155,48 @@ public async Task DownloadAndInstallUpdateAsync(CancellationToken cancellationTo
154155
using var response = await _httpClient.SendAsync(downloadRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
155156
response.EnsureSuccessStatusCode();
156157

157-
await using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
158-
await using var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None, 81920, true);
159-
await contentStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
158+
// Use explicit block so streams are disposed before returning
159+
{
160+
await using var contentStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
161+
await using var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None, 81920, true);
162+
await contentStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
163+
}
164+
165+
_downloadedInstallerPath = tempPath;
166+
_logService.Log(LogLevel.Info, $"Update downloaded to {tempPath}");
167+
}
168+
169+
public void LaunchInstallerAndRestart()
170+
{
171+
if (string.IsNullOrEmpty(_downloadedInstallerPath))
172+
throw new InvalidOperationException("No update has been downloaded.");
160173

161-
_logService.Log(LogLevel.Info, $"Update downloaded to {tempPath}, launching installer...");
174+
string appDir = AppContext.BaseDirectory;
175+
bool isPortable = _fileSystemService.FileExists(_fileSystemService.CombinePath(appDir, "portable.marker"));
176+
string appExePath = _fileSystemService.CombinePath(appDir, "Winhance.exe");
162177

163-
// Launch the installer
164-
await _processExecutor.ShellExecuteAsync(tempPath).ConfigureAwait(false);
178+
string installerArgs;
179+
if (isPortable)
180+
{
181+
installerArgs = $"/SILENT /SUPPRESSMSGBOXES /DIR=\"{appDir.TrimEnd(Path.DirectorySeparatorChar)}\" /MERGETASKS=\"portableinstall\"";
182+
}
183+
else
184+
{
185+
installerArgs = "/SILENT /SUPPRESSMSGBOXES /MERGETASKS=\"regularinstall\\desktopicon,regularinstall\\startmenuicon\"";
186+
}
187+
188+
_logService.Log(LogLevel.Info, $"Launching installer (portable: {isPortable}), app will restart after install...");
165189

166-
_logService.Log(LogLevel.Info, "Installer launched successfully");
190+
// Use cmd /c to: run installer (wait for it to finish) then relaunch the app.
191+
// The caller should exit the application immediately after this call.
192+
var cmdArgs = $"/c start /wait \"\" \"{_downloadedInstallerPath}\" {installerArgs} && start \"\" \"{appExePath}\"";
193+
Process.Start(new ProcessStartInfo
194+
{
195+
FileName = "cmd.exe",
196+
Arguments = cmdArgs,
197+
UseShellExecute = false,
198+
CreateNoWindow = true
199+
});
167200
}
168201

169202
private VersionInfo CreateDefaultVersion()

src/Winhance.UI/Features/Common/Localization/af.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
"Dialog_Update_NoUpdates_Message": "Jy het die nuutste weergawe van Winhance.",
7070
"Dialog_Update_CheckError_Title": "Opdateringkontrolefout",
7171
"Dialog_Update_CheckError_Message": "Daar het 'n fout voorgekom terwyl daar vir opdaterings gekontroleer is: {0}",
72+
"Dialog_Update_Installed_Title": "Opdatering Gereed",
73+
"Dialog_Update_Installed_Message": "Die opdatering is afgelaai. Klik Herbegin om te installeer en Winhance te herbegin.",
74+
"Dialog_Update_Button_Relaunch": "Herbegin",
7275
"Dialog_ImportConfig_Title": "Voer Konfigurasie In",
7376
"Dialog_ImportConfig_Option_Own_Title": "Voer my eie konfigurasie in",
7477
"Dialog_ImportConfig_Option_Own_Description": "Kies 'n konfigurasielêer vanaf jou rekenaar",

src/Winhance.UI/Features/Common/Localization/ar.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1380,6 +1380,9 @@
13801380
"Dialog_Update_NoUpdates_Message": "لديك أحدث إصدار من Winhance.",
13811381
"Dialog_Update_CheckError_Title": "خطأ في التحقق من التحديثات",
13821382
"Dialog_Update_CheckError_Message": "حدث خطأ أثناء التحقق من التحديثات: {0}",
1383+
"Dialog_Update_Installed_Title": "التحديث جاهز",
1384+
"Dialog_Update_Installed_Message": "تم تنزيل التحديث. انقر فوق إعادة التشغيل للتثبيت وإعادة تشغيل Winhance.",
1385+
"Dialog_Update_Button_Relaunch": "إعادة التشغيل",
13831386
"Dialog_ImportOptions_Message": "اختر كيف تريد استيراد التكوين:",
13841387
"Button_Delete": "حذف",
13851388
"Category_AdvancedTools_StatusText": "أدوات متقدمة لتخصيص Windows",

src/Winhance.UI/Features/Common/Localization/cs.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
"Dialog_Update_NoUpdates_Message": "Máte nejnovější verzi Winhance.",
7070
"Dialog_Update_CheckError_Title": "Chyba kontroly aktualizací",
7171
"Dialog_Update_CheckError_Message": "Při kontrole aktualizací došlo k chybě: {0}",
72+
"Dialog_Update_Installed_Title": "Aktualizace připravena",
73+
"Dialog_Update_Installed_Message": "Aktualizace byla stažena. Klikněte na Restartovat pro instalaci a restartování Winhance.",
74+
"Dialog_Update_Button_Relaunch": "Restartovat",
7275
"Dialog_ImportConfig_Title": "Importovat konfiguraci",
7376
"Dialog_ImportConfig_Option_Own_Title": "Importovat vlastní konfiguraci",
7477
"Dialog_ImportConfig_Option_Own_Description": "Vyberte konfigurační soubor z vašeho počítače",

src/Winhance.UI/Features/Common/Localization/de.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
"Dialog_Update_NoUpdates_Message": "Sie haben die neueste Version von Winhance.",
7070
"Dialog_Update_CheckError_Title": "Fehler bei der Update-Prüfung",
7171
"Dialog_Update_CheckError_Message": "Beim Prüfen auf Updates ist ein Fehler aufgetreten: {0}",
72+
"Dialog_Update_Installed_Title": "Update bereit",
73+
"Dialog_Update_Installed_Message": "Das Update wurde heruntergeladen. Klicken Sie auf Neu starten, um das Update zu installieren und Winhance neu zu starten.",
74+
"Dialog_Update_Button_Relaunch": "Neu starten",
7275
"Dialog_ImportConfig_Title": "Konfiguration importieren",
7376
"Dialog_ImportConfig_Option_Own_Title": "Eigene Konfiguration importieren",
7477
"Dialog_ImportConfig_Option_Own_Description": "Wählen Sie eine Konfigurationsdatei von Ihrem Computer aus",

src/Winhance.UI/Features/Common/Localization/el.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
"Dialog_Update_NoUpdates_Message": "Έχετε την τελευταία έκδοση του Winhance.",
7070
"Dialog_Update_CheckError_Title": "Σφάλμα ελέγχου ενημερώσεων",
7171
"Dialog_Update_CheckError_Message": "Παρουσιάστηκε σφάλμα κατά τον έλεγχο για ενημερώσεις: {0}",
72+
"Dialog_Update_Installed_Title": "Η ενημέρωση είναι έτοιμη",
73+
"Dialog_Update_Installed_Message": "Η ενημέρωση έχει ληφθεί. Κάντε κλικ στο Επανεκκίνηση για εγκατάσταση και επανεκκίνηση του Winhance.",
74+
"Dialog_Update_Button_Relaunch": "Επανεκκίνηση",
7275
"Dialog_ImportConfig_Title": "Εισαγωγή Ρυθμίσεων",
7376
"Dialog_ImportConfig_Option_Own_Title": "Εισαγωγή δικών μου ρυθμίσεων",
7477
"Dialog_ImportConfig_Option_Own_Description": "Επιλέξτε ένα αρχείο ρυθμίσεων από τον υπολογιστή σας",

src/Winhance.UI/Features/Common/Localization/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"Dialog_Update_NoUpdates_Message": "You have the latest version of Winhance.",
7272
"Dialog_Update_CheckError_Title": "Update Check Error",
7373
"Dialog_Update_CheckError_Message": "An error occurred while checking for updates: {0}",
74+
"Dialog_Update_Installed_Title": "Update Ready",
75+
"Dialog_Update_Installed_Message": "The update has been downloaded. Click Relaunch to install and restart Winhance.",
76+
"Dialog_Update_Button_Relaunch": "Relaunch",
7477
"Dialog_ImportConfig_Title": "Import Config",
7578
"Dialog_ImportConfig_Option_Own_Title": "Import my own config",
7679
"Dialog_ImportConfig_Option_Own_Description": "Select a configuration file from your computer",

src/Winhance.UI/Features/Common/Localization/es.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
"Dialog_Update_NoUpdates_Message": "Tienes la última versión de Winhance.",
7070
"Dialog_Update_CheckError_Title": "Error al buscar actualizaciones",
7171
"Dialog_Update_CheckError_Message": "Se produjo un error al buscar actualizaciones: {0}",
72+
"Dialog_Update_Installed_Title": "Actualización lista",
73+
"Dialog_Update_Installed_Message": "La actualización se ha descargado. Haz clic en Relanzar para instalar y reiniciar Winhance.",
74+
"Dialog_Update_Button_Relaunch": "Reiniciar",
7275
"Dialog_ImportConfig_Title": "Importar Configuración",
7376
"Dialog_ImportConfig_Option_Own_Title": "Importar mi propia configuración",
7477
"Dialog_ImportConfig_Option_Own_Description": "Selecciona un archivo de configuración de tu equipo",

0 commit comments

Comments
 (0)