feat: implement application restart functionality and update UI reload options

This commit is contained in:
Lyz Coote
2026-02-18 13:16:33 +01:00
parent be2c3b749c
commit af7d8a0792
6 changed files with 76 additions and 15 deletions

27
app.go
View File

@@ -4,8 +4,10 @@ package main
import (
"context"
"fmt"
"log"
"os"
"os/exec"
"strings"
"sync"
"time"
@@ -141,6 +143,31 @@ func (a *App) QuitApp() {
os.Exit(133)
}
// RestartApp performs a full application restart, including the Go backend.
// It schedules a new process via PowerShell with a short delay to ensure the
// single-instance lock is released before the new instance starts, then exits.
func (a *App) RestartApp() error {
exe, err := os.Executable()
if err != nil {
Log("RestartApp: failed to get executable path:", err)
return err
}
// Escape single quotes in the path for PowerShell string literal
safePath := strings.ReplaceAll(exe, "'", "''")
script := fmt.Sprintf(`Start-Sleep -Seconds 1; Start-Process '%s'`, safePath)
cmd := exec.Command("powershell", "-WindowStyle", "Hidden", "-Command", script)
if err := cmd.Start(); err != nil {
Log("RestartApp: failed to schedule restart:", err)
return err
}
Log("RestartApp: scheduled restart, quitting current instance...")
runtime.Quit(a.ctx)
return nil
}
// =============================================================================
// Configuration Management
// =============================================================================

View File

@@ -1,11 +1,11 @@
[EMLy]
SDK_DECODER_SEMVER = 1.4.2
SDK_DECODER_RELEASE_CHANNEL = beta
GUI_SEMVER = 1.6.0
GUI_SEMVER = 1.6.1
GUI_RELEASE_CHANNEL = beta
LANGUAGE = it
UPDATE_CHECK_ENABLED = false
UPDATE_PATH =
UPDATE_CHECK_ENABLED = true
UPDATE_PATH = "\\dc-rm2\logo\update"
UPDATE_AUTO_CHECK = false
BUGREPORT_API_URL = "https://api.emly.ffois.it"
BUGREPORT_API_KEY = "emly_1BaQdBknsMGcY5DynSby71JnWOKXtJvnuUprkgWT0pujpLFxj5HaTXP9vtJAMk63"

View File

@@ -41,9 +41,11 @@
"settings_danger_reset_label": "Reset App Data",
"settings_danger_reset_hint": "This will clear all your settings and return the app to its default state.",
"settings_danger_reset_button": "Reset data",
"settings_danger_reload_label": "Reload App",
"settings_danger_reload_ui_label": "Reload UI",
"settings_danger_reload_app_label": "Reload App",
"settings_danger_reload_hint": "Reloads the application interface. Useful if the UI becomes unresponsive.",
"settings_danger_reload_button": "Reload",
"settings_danger_reload_button_ui": "Reload UI",
"settings_danger_reload_button_app": "Reload app",
"settings_danger_reset_dialog_title": "Are you absolutely sure?",
"settings_danger_reset_dialog_description": "This action cannot be undone. This will permanently delete your current settings and return the app to its default state.",
"settings_danger_reset_dialog_cancel": "Cancel",

View File

@@ -41,9 +41,11 @@
"settings_danger_reset_label": "Reimposta Dati App",
"settings_danger_reset_hint": "Questo cancellerà tutte le tue impostazioni e riporterà l'app allo stato predefinito.",
"settings_danger_reset_button": "Reimposta dati",
"settings_danger_reload_label": "Ricarica App",
"settings_danger_reload_ui_label": "Ricarica UI",
"settings_danger_reload__app_label": "Ricarica App",
"settings_danger_reload_hint": "Ricarica l'interfaccia dell'applicazione. Utile se l'UI non risponde.",
"settings_danger_reload_button": "Ricarica",
"settings_danger_reload_button_ui": "Ricarica UI",
"settings_danger_reload_button_app": "Ricarica app",
"settings_danger_reset_dialog_title": "Sei assolutamente sicuro?",
"settings_danger_reset_dialog_description": "Questa azione non può essere annullata. Questo eliminerà permanentemente le tue impostazioni attuali e riporterà l'app allo stato predefinito.",
"settings_danger_reset_dialog_cancel": "Annulla",

View File

@@ -298,8 +298,8 @@
href="/"
class={`${buttonVariants({ variant: "destructive" })} cursor-pointer hover:cursor-pointer`}
style="text-decoration: none; margin-left: auto; height: 24px; font-size: 12px; padding: 0 8px;"
aria-label={m.settings_danger_reload_button()}
title={m.settings_danger_reload_button() + " app"}
aria-label={m.settings_danger_reload_button_ui()}
title={m.settings_danger_reload_button_ui()}
>
<RefreshCcwDot />
</a>
@@ -308,8 +308,8 @@
href="#"
class={`${buttonVariants({ variant: "destructive" })} cursor-pointer hover:cursor-pointer`}
style="text-decoration: none; height: 24px; font-size: 12px; padding: 0 8px;"
aria-label={m.settings_danger_reload_button()}
title={m.settings_danger_reload_button() + " app"}
aria-label={m.settings_danger_reload_button_ui()}
title={m.settings_danger_reload_button_ui() }
onclick={() => {
$bugReportDialogOpen = !$bugReportDialogOpen;
}}

View File

@@ -6,7 +6,7 @@
import { Label } from "$lib/components/ui/label";
import { Separator } from "$lib/components/ui/separator";
import { Switch } from "$lib/components/ui/switch";
import { ChevronLeft, Flame, Download, Upload, RefreshCw, CheckCircle2, AlertCircle, Sun, Moon } from "@lucide/svelte";
import { ChevronLeft, Flame, Download, Upload, RefreshCw, CheckCircle2, AlertCircle, Sun, Moon, RefreshCcw } from "@lucide/svelte";
import type { EMLy_GUI_Settings } from "$lib/types";
import { toast } from "svelte-sonner";
import { It, Us } from "svelte-flags";
@@ -25,7 +25,7 @@
import { setLocale } from "$lib/paraglide/runtime";
import { mailState } from "$lib/stores/mail-state.svelte.js";
import { dev } from '$app/environment';
import { ExportSettings, ImportSettings, CheckForUpdates, DownloadUpdate, InstallUpdate, GetUpdateStatus, SetUpdateCheckerEnabled } from "$lib/wailsjs/go/main/App";
import { ExportSettings, ImportSettings, CheckForUpdates, DownloadUpdate, InstallUpdate, GetUpdateStatus, SetUpdateCheckerEnabled, RestartApp } from "$lib/wailsjs/go/main/App";
import { EventsOn, EventsOff } from "$lib/wailsjs/runtime/runtime";
let { data } = $props();
@@ -257,6 +257,16 @@
}
}
async function restartEntireApp() {
try {
await RestartApp();
} catch(e) {
toast.error("Error while trying to reload the app");
console.error(e);
}
}
// Update System State
type UpdateStatus = {
currentVersion: string;
@@ -858,7 +868,7 @@
class="flex items-center justify-between gap-4 rounded-lg border border-destructive/30 bg-card p-4"
>
<div class="space-y-1">
<Label class="text-sm">{m.settings_danger_reload_label()}</Label>
<Label class="text-sm">{m.settings_danger_reload_ui_label()}</Label>
<div class="text-sm text-muted-foreground">
{m.settings_danger_reload_hint()}
</div>
@@ -870,9 +880,29 @@
class={`${buttonVariants({ variant: "destructive" })} cursor-pointer hover:cursor-pointer`}
style="text-decoration: none;"
>
{m.settings_danger_reload_button()}
{m.settings_danger_reload_button_ui()}
</a>
</div>
<div
class="flex items-center justify-between gap-4 rounded-lg border border-destructive/30 bg-card p-4"
>
<div class="space-y-1">
<Label class="text-sm">{m.settings_danger_reload_app_label()}</Label>
<div class="text-sm text-muted-foreground">
{m.settings_danger_reload_hint()}
</div>
</div>
<Button
class={`${buttonVariants({ variant: "destructive" })} cursor-pointer hover:cursor-pointer`}
onclick={restartEntireApp}
style="text-decoration: none;"
>
{m.settings_danger_reload_button_app()}
</Button>
</div>
<Separator />
<div