From 4b09d2133de3573fc925bdae7f6256e198da35a6 Mon Sep 17 00:00:00 2001 From: Shreyas D R Date: Fri, 3 Apr 2026 00:14:03 +0530 Subject: [PATCH] feat(windows): add GUI uninstaller script Adds a Windows-specific uninstaller under windows/uninstaller/ that: - Shows a Yes/No confirmation dialog via Windows Forms - Displays a live progress window (no console) during removal - Removes app files, Start Menu/Desktop/Startup shortcuts, AppData configuration, and all registry entries - Mirrors paths/keys from the Inno Setup installer (inno_setup.iss) - Includes a Register-SpotubeUninstaller.ps1 helper to surface the uninstaller in Control Panel -> Programs and Features - Provides a .bat wrapper (WindowStyle Hidden) so only GUI dialogs show Closes: N/A --- .../Register-SpotubeUninstaller.ps1 | 85 ++++++++ windows/uninstaller/Uninstall-Spotube.bat | 4 + windows/uninstaller/Uninstall-Spotube.ps1 | 203 ++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 windows/uninstaller/Register-SpotubeUninstaller.ps1 create mode 100644 windows/uninstaller/Uninstall-Spotube.bat create mode 100644 windows/uninstaller/Uninstall-Spotube.ps1 diff --git a/windows/uninstaller/Register-SpotubeUninstaller.ps1 b/windows/uninstaller/Register-SpotubeUninstaller.ps1 new file mode 100644 index 00000000..cbd8dca6 --- /dev/null +++ b/windows/uninstaller/Register-SpotubeUninstaller.ps1 @@ -0,0 +1,85 @@ +<# +.SYNOPSIS + Registers the Spotube custom uninstaller in Windows Programs and Features. +.DESCRIPTION + Writes a registry entry to HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall + so that Spotube appears in Control Panel -> Programs and Features and in + Settings -> Apps -> Installed Apps. The UninstallString points to Uninstall-Spotube.bat + which must be in the same directory as this script. +.NOTES + Requires: Uninstall-Spotube.bat in the same folder. + Run as Administrator. +#> +param() + +# Re-elevate if not already running as Administrator. +$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator +) +if (-not $isAdmin) { + Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs + exit +} + +$scriptDir = Split-Path -Parent $PSCommandPath +$uninstallBat = Join-Path $scriptDir "Uninstall-Spotube.bat" + +if (-Not (Test-Path $uninstallBat)) { + Write-Error "Uninstall-Spotube.bat not found in '$scriptDir'. Ensure all uninstaller files are kept together." + pause + exit 1 +} + +# Version sourced from pubspec.yaml (5.1.1+44). Override if the installed exe exposes a FileVersion. +$displayVersion = "5.1.1" +$iconPath = "" + +foreach ($candidate in @( + (Join-Path $env:ProgramFiles "Spotube\spotube.exe"), + (Join-Path $env:LOCALAPPDATA "Programs\Spotube\spotube.exe") +)) { + if (Test-Path $candidate) { + $fileVer = (Get-Item $candidate).VersionInfo.FileVersion + if ($fileVer) { $displayVersion = $fileVer } + $iconPath = $candidate + break + } +} + +$regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SpotubeCustomUninstaller" + +if (-Not (Test-Path $regPath)) { + New-Item -Path $regPath -Force | Out-Null +} + +# Registry values follow the standard Windows "Add/Remove Programs" schema. +$stringValues = @{ + DisplayName = "Spotube" + DisplayVersion = $displayVersion + Publisher = "KRTirtho, OSS" + URLInfoAbout = "https://github.com/KRTirtho/spotube" + HelpLink = "https://github.com/KRTirtho/spotube/issues" + UninstallString = "`"$uninstallBat`"" + InstallDate = (Get-Date -Format "yyyyMMdd") +} +$dwordValues = @{ + NoModify = 1 + NoRepair = 1 + EstimatedSize = 80000 # Approximate installed size in KB +} + +foreach ($kv in $stringValues.GetEnumerator()) { + Set-ItemProperty -Path $regPath -Name $kv.Key -Value $kv.Value +} +foreach ($kv in $dwordValues.GetEnumerator()) { + Set-ItemProperty -Path $regPath -Name $kv.Key -Value $kv.Value -Type DWord +} +if ($iconPath) { + Set-ItemProperty -Path $regPath -Name "DisplayIcon" -Value "$iconPath,0" +} + +Write-Host "" +Write-Host "Spotube registered in Programs and Features." -ForegroundColor Green +Write-Host "Open Control Panel -> Programs and Features (or Settings -> Apps) to uninstall." +Write-Host "" +pause diff --git a/windows/uninstaller/Uninstall-Spotube.bat b/windows/uninstaller/Uninstall-Spotube.bat new file mode 100644 index 00000000..7f404a78 --- /dev/null +++ b/windows/uninstaller/Uninstall-Spotube.bat @@ -0,0 +1,4 @@ +@echo off +:: Launches the Spotube GUI uninstaller without showing a console window. +:: -WindowStyle Hidden ensures only the WinForms dialogs are visible. +powershell -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0Uninstall-Spotube.ps1" diff --git a/windows/uninstaller/Uninstall-Spotube.ps1 b/windows/uninstaller/Uninstall-Spotube.ps1 new file mode 100644 index 00000000..16acd7dc --- /dev/null +++ b/windows/uninstaller/Uninstall-Spotube.ps1 @@ -0,0 +1,203 @@ +<# +.SYNOPSIS + GUI-based uninstaller for Spotube on Windows. +.DESCRIPTION + Removes all Spotube installation artifacts: application files, shortcuts, + user data, and registry entries. Mirrors what the Inno Setup installer + creates (inno_setup.iss / make_config.yaml). +.PARAMETER Silent + Suppresses all GUI dialogs and runs non-interactively. +#> +param ( + [switch]$Silent +) + +# Application metadata — must match Inno Setup make_config.yaml +$APP_NAME = "Spotube" +$APP_ID = "80B901C8-D6FE-494E-8AF7-A2BD440E8644" +$INNO_REG_KEY = "${APP_ID}_is1" +$CUSTOM_REG_KEY = "SpotubeCustomUninstaller" + +Add-Type -AssemblyName System.Windows.Forms +Add-Type -AssemblyName System.Drawing + +# Displays a standard Windows message box and returns the DialogResult. +function Show-MessageBox { + param( + [string]$Message, + [string]$Title = "Spotube Uninstaller", + [System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK, + [System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::Information + ) + return [System.Windows.Forms.MessageBox]::Show($Message, $Title, $Buttons, $Icon) +} + +# Creates and displays the progress window. Returns a hashtable of controls +# so the caller can update label text, sub-label, and progress bar value. +function Show-ProgressForm { + $form = New-Object System.Windows.Forms.Form + $form.Text = "Spotube Uninstaller" + $form.Size = New-Object System.Drawing.Size(460, 200) + $form.StartPosition = "CenterScreen" + $form.FormBorderStyle = "FixedDialog" + $form.MaximizeBox = $false + $form.MinimizeBox = $false + $form.ControlBox = $false # Disable X button during active uninstall + $form.TopMost = $true + + # Use the installed Spotube executable's icon if available + foreach ($candidate in @( + (Join-Path $env:ProgramFiles "Spotube\spotube.exe"), + (Join-Path $env:LOCALAPPDATA "Programs\Spotube\spotube.exe") + )) { + if (Test-Path $candidate) { + try { $form.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($candidate) } catch {} + break + } + } + + $lblStatus = New-Object System.Windows.Forms.Label + $lblStatus.Location = New-Object System.Drawing.Point(16, 16) + $lblStatus.Size = New-Object System.Drawing.Size(420, 20) + $lblStatus.Text = "Preparing..." + $lblStatus.Font = New-Object System.Drawing.Font("Segoe UI", 10) + $form.Controls.Add($lblStatus) + + $progressBar = New-Object System.Windows.Forms.ProgressBar + $progressBar.Location = New-Object System.Drawing.Point(16, 48) + $progressBar.Size = New-Object System.Drawing.Size(420, 22) + $progressBar.Minimum = 0 + $progressBar.Maximum = 100 + $progressBar.Value = 0 + $form.Controls.Add($progressBar) + + $lblDetail = New-Object System.Windows.Forms.Label + $lblDetail.Location = New-Object System.Drawing.Point(16, 80) + $lblDetail.Size = New-Object System.Drawing.Size(420, 16) + $lblDetail.Text = "" + $lblDetail.Font = New-Object System.Drawing.Font("Segoe UI", 8) + $lblDetail.ForeColor = [System.Drawing.Color]::DimGray + $form.Controls.Add($lblDetail) + + $form.Show() + $form.Refresh() + + return @{ + Form = $form + Status = $lblStatus + Detail = $lblDetail + Progress = $progressBar + } +} + +# Re-elevate as Administrator if the script is not already running elevated. +$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator +) +if (-not $isAdmin) { + $relaunchArgs = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" + if ($Silent) { $relaunchArgs += " -Silent" } + Start-Process powershell -ArgumentList $relaunchArgs -Verb RunAs + exit +} + +# Prompt the user before making any changes. +if (-not $Silent) { + $confirmMsg = @" +Are you sure you want to uninstall Spotube? + +This will permanently remove: + • Application files + • Desktop, Start Menu, and Startup shortcuts + • User configuration and cached data + • Windows registry entries +"@ + $result = Show-MessageBox -Message $confirmMsg -Title "Uninstall Spotube" ` + -Buttons ([System.Windows.Forms.MessageBoxButtons]::YesNo) ` + -Icon ([System.Windows.Forms.MessageBoxIcon]::Question) + + if ($result -ne [System.Windows.Forms.DialogResult]::Yes) { + Show-MessageBox -Message "Uninstallation was cancelled. No changes were made." ` + -Title "Cancelled" -Icon ([System.Windows.Forms.MessageBoxIcon]::Information) + exit + } +} + +$ui = Show-ProgressForm + +# Updates the progress window with new status text and a percentage value. +function Update-Progress ([string]$status, [string]$detail, [int]$percent) { + $ui.Status.Text = $status + $ui.Detail.Text = $detail + $ui.Progress.Value = [Math]::Min($percent, 100) + $ui.Form.Refresh() +} + +# Silently removes a file or directory; no-ops if the path does not exist. +function Safe-Remove ([string]$path) { + if ($path -and (Test-Path $path)) { + try { Remove-Item -Path $path -Recurse -Force -ErrorAction Stop } catch {} + } +} + +# Step 1: Terminate any running Spotube processes before touching files. +Update-Progress "Stopping Spotube..." "Terminating running processes" 5 +Get-Process -Name "spotube" -ErrorAction SilentlyContinue | + Stop-Process -Force -ErrorAction SilentlyContinue +Start-Sleep -Milliseconds 1500 + +# Step 2: Delete the installation directory. +# Inno Setup installs to {autopf}\Spotube — covers both admin and per-user installs. +Update-Progress "Removing application files..." "Deleting installation directory" 20 +@( + (Join-Path $env:ProgramFiles $APP_NAME), + (Join-Path $env:ProgramW6432 $APP_NAME), + (Join-Path $env:LOCALAPPDATA "Programs\$APP_NAME") +) | Select-Object -Unique | ForEach-Object { Safe-Remove $_ } + +# Step 3: Remove shortcuts created by the Inno Setup [Icons] section. +# Covers: {autoprograms} (Start Menu), {autodesktop} (Desktop), {userstartup} (Startup). +Update-Progress "Removing shortcuts..." "Cleaning Start Menu, Desktop, and Startup" 40 +@( + (Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$APP_NAME.lnk"), + (Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\$APP_NAME.lnk"), + (Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$APP_NAME"), + (Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\$APP_NAME"), + (Join-Path ([Environment]::GetFolderPath("CommonDesktopDirectory")) "$APP_NAME.lnk"), + (Join-Path ([Environment]::GetFolderPath("Desktop")) "$APP_NAME.lnk"), + (Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\$APP_NAME.lnk") +) | ForEach-Object { Safe-Remove $_ } + +# Step 4: Remove Flutter application data stored in AppData. +Update-Progress "Removing user data..." "Clearing configuration and cache" 60 +@( + (Join-Path $env:APPDATA "com.krtirtho.spotube"), + (Join-Path $env:LOCALAPPDATA "com.krtirtho.spotube"), + (Join-Path $env:APPDATA "spotube"), + (Join-Path $env:LOCALAPPDATA "spotube") +) | ForEach-Object { Safe-Remove $_ } + +# Step 5: Remove all Windows registry entries. +# Targets the Inno Setup key ({AppId}_is1) and our custom Control Panel key. +Update-Progress "Removing registry entries..." "Cleaning uninstall records" 80 +foreach ($root in @("HKLM:\SOFTWARE", "HKCU:\SOFTWARE", "HKLM:\SOFTWARE\WOW6432Node")) { + foreach ($key in @($INNO_REG_KEY, $CUSTOM_REG_KEY)) { + Safe-Remove "$root\Microsoft\Windows\CurrentVersion\Uninstall\$key" + } +} +Safe-Remove "HKCU:\SOFTWARE\KRTirtho" +Safe-Remove "HKCU:\SOFTWARE\Spotube" + +Update-Progress "Complete" "Spotube has been removed." 100 +Start-Sleep -Milliseconds 500 +$ui.Form.Close() +$ui.Form.Dispose() + +# Show the final confirmation dialog with an OK button to dismiss. +if (-not $Silent) { + Show-MessageBox ` + -Message "Spotube has been successfully uninstalled.`n`nClick OK to close." ` + -Title "Uninstall Complete" ` + -Buttons ([System.Windows.Forms.MessageBoxButtons]::OK) ` + -Icon ([System.Windows.Forms.MessageBoxIcon]::Information) +}