updating Windows install experience

This commit is contained in:
2025-08-26 18:37:08 -05:00
committed by Jason Ross
parent 479571f619
commit 72fd4a92f4
7 changed files with 156 additions and 6 deletions
+35 -2
View File
@@ -17,6 +17,39 @@ chmod +x dist/android-file-handler
# this ensures the package installs /usr/local/bin/android-file-handler (no extra dist/ prefix)
# Debian
# Prepare packaging layout in a separate directory to avoid clobbering build artifacts
PKG_DIR="pkg_dist"
rm -rf "$PKG_DIR"
mkdir -p "$PKG_DIR/usr/local/bin" \
"$PKG_DIR/usr/share/applications" \
"$PKG_DIR/usr/share/icons/hicolor/256x256/apps"
# Copy built binary
cp dist/android-file-handler "$PKG_DIR/usr/local/bin/android-file-handler"
chmod 0755 "$PKG_DIR/usr/local/bin/android-file-handler"
# Create .desktop file
cat > "$PKG_DIR/usr/share/applications/android-file-handler.desktop" <<'EOF'
[Desktop Entry]
Type=Application
Name=Android File Handler
Comment=Manage Android device files via ADB
Exec=/usr/local/bin/android-file-handler %U
Icon=android-file-handler
Terminal=false
Categories=Utility;Development;
StartupNotify=true
EOF
chmod 644 "$PKG_DIR/usr/share/applications/android-file-handler.desktop"
# Copy icon if present in repo (fallback optional)
if [ -f "assets/icons/android-file-handler-256.png" ]; then
cp assets/icons/android-file-handler-256.png "$PKG_DIR/usr/share/icons/hicolor/256x256/apps/android-file-handler.png"
chmod 644 "$PKG_DIR/usr/share/icons/hicolor/256x256/apps/android-file-handler.png"
fi
# Build the Debian package and include postinst script
fpm -s dir -t deb -n android-file-handler -v "$VERSION" \
--architecture amd64 --prefix /usr/local/bin --deb-user root --deb-group root \
-p "dist/android-file-handler_${VERSION}_amd64.deb" -C dist android-file-handler
--architecture amd64 --prefix /usr/local/bin --deb-user root --deb-group root \
--after-install scripts/debian/postinst.sh \
-p "dist/android-file-handler_${VERSION}_amd64.deb" -C "$PKG_DIR" usr/local/bin/android-file-handler usr/share/applications/android-file-handler.desktop usr/share/icons/hicolor/256x256/apps/android-file-handler.png
+26
View File
@@ -0,0 +1,26 @@
#!/bin/sh
set -e
# Post-installation script for android-file-handler
# - update desktop database if available
# - update icon cache if available
# - ensure binary is executable
# Update desktop database if the utility exists
if command -v update-desktop-database >/dev/null 2>&1; then
update-desktop-database /usr/share/applications || true
fi
# Update GTK icon cache for hicolor theme if utility exists
if command -v gtk-update-icon-cache >/dev/null 2>&1; then
if [ -d /usr/share/icons/hicolor ]; then
gtk-update-icon-cache -t -f /usr/share/icons/hicolor || true
fi
fi
# Ensure installed binary is executable
if [ -f /usr/local/bin/android-file-handler ]; then
chmod 0755 /usr/local/bin/android-file-handler || true
fi
exit 0
@@ -43,5 +43,4 @@ exe = EXE(
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon='icon_media/robot_files_256.png',
)
@@ -4,7 +4,7 @@ a = Analysis(
['src/main.py'],
pathex=['src'],
binaries=[],
datas=[('src/gui', 'gui')],
datas=[('src/gui', 'gui'), ('../scripts/windows/first_run_install.ps1', 'scripts/windows')],
hiddenimports=[
'gui',
'gui.file_browser',
+51
View File
@@ -0,0 +1,51 @@
param(
[string]$ExePath = "$PSScriptRoot\..\..\dist\android-file-handler.exe",
[string]$IconPath = "$PSScriptRoot\..\..\assets\icons\android-file-handler.ico",
[string]$AppName = "Android File Handler"
)
function Ensure-Elevated {
if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
# Relaunch the script with elevation
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = "powershell.exe"
$psi.Arguments = "-ExecutionPolicy Bypass -File `"$PSCommandPath`""
$psi.Verb = "runas"
try {
[System.Diagnostics.Process]::Start($psi) | Out-Null
Exit 0
} catch {
Write-Error "Elevation required to install to Program Files."
Exit 1
}
}
}
Ensure-Elevated
$destDir = Join-Path ${env:ProgramFiles} $AppName
if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir | Out-Null }
$resolvedExe = Resolve-Path -Path $ExePath -ErrorAction SilentlyContinue
if (-not $resolvedExe) {
Write-Error "Application executable not found at $ExePath"
Exit 1
}
Copy-Item -Path $resolvedExe -Destination (Join-Path $destDir (Split-Path $resolvedExe -Leaf)) -Force
# Create Start Menu shortcut
$programs = Join-Path $env:APPDATA 'Microsoft\Windows\Start Menu\Programs'
$appFolder = Join-Path $programs $AppName
if (-not (Test-Path $appFolder)) { New-Item -ItemType Directory -Path $appFolder | Out-Null }
$shortcutPath = Join-Path $appFolder "$AppName.lnk"
$wsh = New-Object -ComObject WScript.Shell
$sc = $wsh.CreateShortcut($shortcutPath)
$sc.TargetPath = (Join-Path $destDir (Split-Path $resolvedExe -Leaf))
$sc.WorkingDirectory = $destDir
if (Test-Path $IconPath) { $sc.IconLocation = Resolve-Path $IconPath }
$sc.Save()
Write-Output "Installed $AppName to $destDir and created Start Menu shortcut."
Exit 0
+41 -2
View File
@@ -9,6 +9,9 @@ import tkinter as tk
from tkinter import messagebox, scrolledtext
import tempfile
import stat
import subprocess
import sys
import os
def get_license_file_path() -> str:
@@ -104,12 +107,48 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE."""
def resource_path(relative_path: str) -> str:
"""Return absolute path to resource for dev and frozen runs."""
try:
if getattr(sys, "frozen", False):
base = getattr(sys, "_MEIPASS", os.path.dirname(sys.executable))
else:
base = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
return os.path.normpath(os.path.join(base, relative_path))
except Exception:
return os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), relative_path))
def run_windows_first_run_if_needed() -> None:
"""If running on Windows and license not agreed, launch first-run installer script.
Uses `resource_path` to locate the bundled PowerShell script in both dev and frozen modes.
"""
try:
if not sys.platform.startswith("win"):
return
if check_license_agreement():
return
script_rel = os.path.join("scripts", "windows", "first_run_install.ps1")
script_path = resource_path(script_rel)
if not os.path.exists(script_path):
return
try:
subprocess.Popen(["powershell.exe", "-ExecutionPolicy", "Bypass", "-File", script_path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except Exception:
pass
except Exception:
pass
class LicenseAgreementFrame(tk.Frame):
"""License agreement UI frame that can be embedded in the main window."""
def __init__(self, parent, on_agree_callback):
"""Initialize the license agreement frame.
Args:
parent: Parent widget
on_agree_callback: Function to call when user agrees to license
+2
View File
@@ -5,7 +5,9 @@ Simple entry point to launch the Android file transfer application.
"""
from gui.main_window import main
from gui.license_agreement import run_windows_first_run_if_needed
if __name__ == "__main__":
run_windows_first_run_if_needed()
main()