Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zinnia",
"version": "0.1.3",
"version": "0.1.4",
"private": true,
"description": "Cross-platform 7z GUI built with Tauri.",
"type": "module",
Expand Down
29 changes: 28 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,31 @@ fn cancel_7z(state: tauri::State<'_, RunningProcess>) -> Result<(), String> {
#[cfg(windows)]
const ARCHIVE_EXTENSIONS: &[&str] = SUPPORTED_ARCHIVE_EXTENSIONS;

#[cfg(windows)]
fn notify_shell_association_changed() {
#[allow(non_snake_case)]
unsafe extern "system" {
fn SHChangeNotify(
wEventId: u32,
uFlags: u32,
dwItem1: *const std::ffi::c_void,
dwItem2: *const std::ffi::c_void,
);
}

const SHCNE_ASSOCCHANGED: u32 = 0x0800_0000;
const SHCNF_IDLIST: u32 = 0x0000;

unsafe {
SHChangeNotify(
SHCNE_ASSOCCHANGED,
SHCNF_IDLIST,
std::ptr::null(),
std::ptr::null(),
);
}
}

#[tauri::command]
fn register_windows_context_menu() -> Result<(), String> {
#[cfg(windows)]
Expand All @@ -699,7 +724,7 @@ fn register_windows_context_menu() -> Result<(), String> {
.create_subkey("Software\\Classes")
.map_err(|e| e.to_string())?;

let icon_value = format!("{},0", exe_str);
let icon_value = format!("\"{}\",0", exe_str);
let compress_entries = [
("*\\shell\\Zinnia", "Compress with Zinnia"),
("Directory\\shell\\Zinnia", "Compress folder with Zinnia"),
Expand Down Expand Up @@ -758,6 +783,7 @@ fn register_windows_context_menu() -> Result<(), String> {
.map_err(|e| e.to_string())?;
}

notify_shell_association_changed();
Ok(())
}

Expand Down Expand Up @@ -807,6 +833,7 @@ fn unregister_windows_context_menu() -> Result<(), String> {
Err(e) => return Err(format!("Failed to remove Zinnia.Archive: {}", e)),
}

notify_shell_association_changed();
Ok(())
}

Expand Down
4 changes: 2 additions & 2 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ <h2 id="settings-title">Settings</h2>

<div class="setting-item">
<div class="setting-info">
<span class="setting-title">Check for updates on startup</span>
<span class="setting-desc">Automatically check for new versions when the app opens.</span>
<span class="setting-title">Check and automatically download updates on startup</span>
<span class="setting-desc">Automatically checks for updates when the app opens and downloads them in the background.</span>
</div>
<label class="switch" data-update-ui>
<input type="checkbox" id="s-auto-check-updates" checked />
Expand Down
46 changes: 22 additions & 24 deletions src/updater.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
import { message, ask, confirm } from "@tauri-apps/plugin-dialog";
import { message, ask } from "@tauri-apps/plugin-dialog";
import { isPermissionGranted, requestPermission, sendNotification } from "@tauri-apps/plugin-notification";
import { log, devLog, setStatus } from "./ui";

Expand All @@ -15,6 +15,22 @@ export async function notify(title: string, body: string) {
}
}

async function promptInstallAndRestart(version: string, install: () => Promise<void>) {
setStatus("Update ready");
const restart = await ask(
`Version ${version} has been downloaded and is ready to install.\n\nRestart now to apply the update?`,
{ title: "Update ready", kind: "info", okLabel: "Restart now", cancelLabel: "Later" }
);
if (restart) {
setStatus("Installing update");
await install();
await relaunch();
} else {
await notify("Zinnia", "Update downloaded. Install it later from Check now.");
setStatus("Idle");
}
}

export async function checkUpdates() {
try {
setStatus("Checking updates");
Expand All @@ -26,18 +42,10 @@ export async function checkUpdates() {
return;
}
log(`Update available: ${update.version}`);
const confirmed = await confirm(
`Version ${update.version} is available. Download and install now?\n\nThe app will restart after installation.`,
{ title: "Update available", kind: "info", okLabel: "Install" }
);
if (!confirmed) {
setStatus("Idle");
return;
}
setStatus("Downloading update");
await update.downloadAndInstall();
log("Update installed. Relaunching...");
await relaunch();
await update.download();
log(`Update ${update.version} downloaded and ready to install.`);
await promptInstallAndRestart(update.version, () => update.install());
} catch (err) {
const messageText = err instanceof Error ? err.message : String(err);
log(`Updater error: ${messageText}`);
Expand All @@ -56,19 +64,9 @@ export async function autoCheckUpdates() {
log(`Update available: ${update.version}`);
await notify("Zinnia Update Available", `Version ${update.version} is available. Downloading in the background...`);
setStatus("Downloading update");
await update.downloadAndInstall();
setStatus("Update ready");
await update.download();
log(`Update ${update.version} downloaded and ready to install.`);
const restart = await ask(
`Version ${update.version} has been downloaded and is ready to install.\n\nRestart now to apply the update?`,
{ title: "Update ready", kind: "info", okLabel: "Restart now", cancelLabel: "Later" }
);
if (restart) {
await relaunch();
} else {
await notify("Zinnia", "Update will be applied next time you restart.");
setStatus("Idle");
}
await promptInstallAndRestart(update.version, () => update.install());
} catch (err) {
const messageText = err instanceof Error ? err.message : String(err);
devLog(`Auto-update error: ${messageText}`);
Expand Down
Loading