)}
- {/* Other stage progress (with visual indicators) */}
- {showOtherStageProgress && (
+ {!updateReady && showOtherStageProgress && (
- {/* Progress indicator for non-downloading stages */}
)}
- {!isUpdating && (
+ {updateReady ? (
- {updateInfo.manual_update_required ? (
-
-
- View Release
-
- ) : (
- void handleUpdateClick()}
- size="sm"
- className="flex gap-2 items-center text-xs"
- >
-
- Update Now
-
- )}
void handleRestartClick()}
size="sm"
- className="text-xs"
+ className="flex gap-2 items-center text-xs"
>
- Later
+
+ Restart Now
+ ) : (
+ !isUpdating && (
+
+ {updateInfo.manual_update_required ? (
+
+
+ View Release
+
+ ) : (
+ void handleUpdateClick()}
+ size="sm"
+ className="flex gap-2 items-center text-xs"
+ >
+
+ Download Update
+
+ )}
+
+ Later
+
+
+ )
)}
diff --git a/src/components/launch-on-login-dialog.tsx b/src/components/launch-on-login-dialog.tsx
new file mode 100644
index 0000000..1b88da8
--- /dev/null
+++ b/src/components/launch-on-login-dialog.tsx
@@ -0,0 +1,96 @@
+"use client";
+
+import { invoke } from "@tauri-apps/api/core";
+import { useCallback, useState } from "react";
+import { LoadingButton } from "@/components/loading-button";
+import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+} from "@/components/ui/dialog";
+import { showErrorToast, showSuccessToast } from "@/lib/toast-utils";
+
+interface LaunchOnLoginDialogProps {
+ isOpen: boolean;
+ onClose: () => void;
+}
+
+export function LaunchOnLoginDialog({
+ isOpen,
+ onClose,
+}: LaunchOnLoginDialogProps) {
+ const [isEnabling, setIsEnabling] = useState(false);
+ const [isDeclining, setIsDeclining] = useState(false);
+
+ const handleEnable = useCallback(async () => {
+ setIsEnabling(true);
+ try {
+ await invoke("enable_launch_on_login");
+ showSuccessToast("Launch on login enabled");
+ onClose();
+ } catch (error) {
+ console.error("Failed to enable launch on login:", error);
+ showErrorToast("Failed to enable launch on login", {
+ description:
+ error instanceof Error ? error.message : "Please try again",
+ });
+ } finally {
+ setIsEnabling(false);
+ }
+ }, [onClose]);
+
+ const handleDecline = useCallback(async () => {
+ setIsDeclining(true);
+ try {
+ await invoke("decline_launch_on_login");
+ onClose();
+ } catch (error) {
+ console.error("Failed to decline launch on login:", error);
+ showErrorToast("Failed to save preference", {
+ description:
+ error instanceof Error ? error.message : "Please try again",
+ });
+ } finally {
+ setIsDeclining(false);
+ }
+ }, [onClose]);
+
+ return (
+
+ );
+}
diff --git a/src/components/theme-provider.tsx b/src/components/theme-provider.tsx
index cb15ae3..ad2f6d3 100644
--- a/src/components/theme-provider.tsx
+++ b/src/components/theme-provider.tsx
@@ -38,7 +38,7 @@ export function CustomThemeProvider({ children }: CustomThemeProviderProps) {
) {
setDefaultTheme(themeValue);
} else if (themeValue === "custom") {
- setDefaultTheme("light");
+ setDefaultTheme("dark");
if (
settings.custom_theme &&
Object.keys(settings.custom_theme).length > 0
diff --git a/src/hooks/use-app-update-notifications.tsx b/src/hooks/use-app-update-notifications.tsx
index c0587ca..1b70c4a 100644
--- a/src/hooks/use-app-update-notifications.tsx
+++ b/src/hooks/use-app-update-notifications.tsx
@@ -13,6 +13,7 @@ export function useAppUpdateNotifications() {
const [isUpdating, setIsUpdating] = useState(false);
const [updateProgress, setUpdateProgress] =
useState
(null);
+ const [updateReady, setUpdateReady] = useState(false);
const [isClient, setIsClient] = useState(false);
const [dismissedVersion, setDismissedVersion] = useState(null);
@@ -68,7 +69,7 @@ export function useAppUpdateNotifications() {
message: "Starting update...",
});
- await invoke("download_and_install_app_update", {
+ await invoke("download_and_prepare_app_update", {
updateInfo: appUpdateInfo,
});
} catch (error) {
@@ -84,6 +85,20 @@ export function useAppUpdateNotifications() {
}
}, []);
+ const handleRestart = useCallback(async () => {
+ try {
+ await invoke("restart_application");
+ } catch (error) {
+ console.error("Failed to restart app:", error);
+ showToast({
+ type: "error",
+ title: "Failed to restart",
+ description: String(error),
+ duration: 6000,
+ });
+ }
+ }, []);
+
const dismissAppUpdate = useCallback(() => {
if (!isClient) return;
@@ -125,6 +140,13 @@ export function useAppUpdateNotifications() {
},
);
+ const unlistenReady = listen("app-update-ready", (event) => {
+ console.log("App update ready:", event.payload);
+ setUpdateReady(true);
+ setIsUpdating(false);
+ setUpdateProgress(null);
+ });
+
return () => {
void unlistenUpdate.then((unlisten) => {
unlisten();
@@ -132,6 +154,9 @@ export function useAppUpdateNotifications() {
void unlistenProgress.then((unlisten) => {
unlisten();
});
+ void unlistenReady.then((unlisten) => {
+ unlisten();
+ });
};
}, [isClient]);
@@ -144,9 +169,11 @@ export function useAppUpdateNotifications() {
),
{
@@ -163,9 +190,11 @@ export function useAppUpdateNotifications() {
}, [
updateInfo,
handleAppUpdate,
+ handleRestart,
dismissAppUpdate,
isUpdating,
updateProgress,
+ updateReady,
isClient,
]);
@@ -181,6 +210,7 @@ export function useAppUpdateNotifications() {
updateInfo,
isUpdating,
updateProgress,
+ updateReady,
checkForAppUpdates,
checkForAppUpdatesManual,
dismissAppUpdate,