mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-06-12 09:47:51 +02:00
165 lines
4.5 KiB
TypeScript
165 lines
4.5 KiB
TypeScript
"use client";
|
|
|
|
import { AppUpdateToast } from "@/components/app-update-toast";
|
|
import { showToast } from "@/lib/toast-utils";
|
|
import type { AppUpdateInfo } from "@/types";
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
import { listen } from "@tauri-apps/api/event";
|
|
import React, { useCallback, useEffect, useState } from "react";
|
|
import { toast } from "sonner";
|
|
|
|
export function useAppUpdateNotifications() {
|
|
const [updateInfo, setUpdateInfo] = useState<AppUpdateInfo | null>(null);
|
|
const [isUpdating, setIsUpdating] = useState(false);
|
|
const [updateProgress, setUpdateProgress] = useState<string>("");
|
|
const [isClient, setIsClient] = useState(false);
|
|
const [dismissedVersion, setDismissedVersion] = useState<string | null>(null);
|
|
|
|
// Ensure we're on the client side to prevent hydration mismatches
|
|
useEffect(() => {
|
|
setIsClient(true);
|
|
}, []);
|
|
|
|
const checkForAppUpdates = useCallback(async () => {
|
|
if (!isClient) return;
|
|
|
|
try {
|
|
const update = await invoke<AppUpdateInfo | null>(
|
|
"check_for_app_updates",
|
|
);
|
|
|
|
// Don't show update if this version was already dismissed
|
|
if (update && update.new_version !== dismissedVersion) {
|
|
setUpdateInfo(update);
|
|
} else if (update) {
|
|
console.log("Update available but dismissed:", update.new_version);
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to check for app updates:", error);
|
|
}
|
|
}, [isClient, dismissedVersion]);
|
|
|
|
const checkForAppUpdatesManual = useCallback(async () => {
|
|
if (!isClient) return;
|
|
|
|
try {
|
|
console.log("Triggering manual app update check...");
|
|
const update = await invoke<AppUpdateInfo | null>(
|
|
"check_for_app_updates_manual",
|
|
);
|
|
console.log("Manual check result:", update);
|
|
|
|
// Always show manual check results, even if previously dismissed
|
|
setUpdateInfo(update);
|
|
} catch (error) {
|
|
console.error("Failed to manually check for app updates:", error);
|
|
}
|
|
}, [isClient]);
|
|
|
|
const handleAppUpdate = useCallback(async (appUpdateInfo: AppUpdateInfo) => {
|
|
try {
|
|
setIsUpdating(true);
|
|
setUpdateProgress("Starting update...");
|
|
|
|
await invoke("download_and_install_app_update", {
|
|
updateInfo: appUpdateInfo,
|
|
});
|
|
} catch (error) {
|
|
console.error("Failed to update app:", error);
|
|
showToast({
|
|
type: "error",
|
|
title: "Failed to update Donut Browser",
|
|
description: String(error),
|
|
duration: 6000,
|
|
});
|
|
setIsUpdating(false);
|
|
setUpdateProgress("");
|
|
}
|
|
}, []);
|
|
|
|
const dismissAppUpdate = useCallback(() => {
|
|
if (!isClient) return;
|
|
|
|
// Remember the dismissed version so we don't show it again
|
|
if (updateInfo) {
|
|
setDismissedVersion(updateInfo.new_version);
|
|
console.log("Dismissed app update version:", updateInfo.new_version);
|
|
}
|
|
|
|
setUpdateInfo(null);
|
|
toast.dismiss("app-update");
|
|
}, [isClient, updateInfo]);
|
|
|
|
// Listen for app update availability
|
|
useEffect(() => {
|
|
if (!isClient) return;
|
|
|
|
const unlistenUpdate = listen<AppUpdateInfo>(
|
|
"app-update-available",
|
|
(event) => {
|
|
console.log("App update available:", event.payload);
|
|
setUpdateInfo(event.payload);
|
|
},
|
|
);
|
|
|
|
const unlistenProgress = listen<string>("app-update-progress", (event) => {
|
|
console.log("App update progress:", event.payload);
|
|
setUpdateProgress(event.payload);
|
|
});
|
|
|
|
return () => {
|
|
void unlistenUpdate.then((unlisten) => {
|
|
unlisten();
|
|
});
|
|
void unlistenProgress.then((unlisten) => {
|
|
unlisten();
|
|
});
|
|
};
|
|
}, [isClient]);
|
|
|
|
// Show toast when update is available
|
|
useEffect(() => {
|
|
if (!isClient || !updateInfo) return;
|
|
|
|
toast.custom(
|
|
() => (
|
|
<AppUpdateToast
|
|
updateInfo={updateInfo}
|
|
onUpdate={handleAppUpdate}
|
|
onDismiss={dismissAppUpdate}
|
|
isUpdating={isUpdating}
|
|
updateProgress={updateProgress}
|
|
/>
|
|
),
|
|
{
|
|
id: "app-update",
|
|
duration: Number.POSITIVE_INFINITY, // Persistent until user action
|
|
position: "top-left",
|
|
},
|
|
);
|
|
}, [
|
|
updateInfo,
|
|
handleAppUpdate,
|
|
dismissAppUpdate,
|
|
isUpdating,
|
|
updateProgress,
|
|
isClient,
|
|
]);
|
|
|
|
// Check for app updates on startup
|
|
useEffect(() => {
|
|
if (!isClient) return;
|
|
|
|
// Check for updates immediately on startup
|
|
void checkForAppUpdates();
|
|
}, [isClient, checkForAppUpdates]);
|
|
|
|
return {
|
|
updateInfo,
|
|
isUpdating,
|
|
checkForAppUpdates,
|
|
checkForAppUpdatesManual,
|
|
dismissAppUpdate,
|
|
};
|
|
}
|