From 359c79a440f61f3c99d7ffa0ec054ee553c61acb Mon Sep 17 00:00:00 2001 From: Lotus CI Date: Thu, 24 Sep 2026 12:51:18 -0400 Subject: [PATCH] feat(desktop): ask once what closing the window should do (cinny-desktop #5) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first time the window is closed, a dialog asks "Keep Lotus Chat running?" — Keep running in the tray (default, focused) / Quit when I close the window — with an opt-in "Start Lotus Chat when I sign in" checkbox in the same moment (per the approved design: one dialog, no wizard). The choice is saved natively; Settings → General → "When I close the window" changes it later (tray / quit / ask me). The dialog is role="dialog" aria-modal, labelled and described, with focus on the default button. Web-side flow verified with a stubbed native side: event → dialog → checkbox + Quit sends autostart enable + resolve_close_request("quit"); the Settings select saves "tray". Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA --- src/app/components/CloseBehaviorPrompt.tsx | 114 ++++++++++++++++++ src/app/features/settings/general/General.tsx | 30 +++++ src/app/pages/client/ClientNonUIFeatures.tsx | 2 + 3 files changed, 146 insertions(+) create mode 100644 src/app/components/CloseBehaviorPrompt.tsx diff --git a/src/app/components/CloseBehaviorPrompt.tsx b/src/app/components/CloseBehaviorPrompt.tsx new file mode 100644 index 000000000..b1bc7bbf7 --- /dev/null +++ b/src/app/components/CloseBehaviorPrompt.tsx @@ -0,0 +1,114 @@ +import React, { useCallback, useEffect, useState } from 'react'; +import FocusTrap from 'focus-trap-react'; +import { + Box, + Button, + Checkbox, + Dialog, + Header, + Overlay, + OverlayBackdrop, + OverlayCenter, + Text, + config, +} from 'folds'; +import { invokeTauri, isTauri, tauriInvoke, useTauriEvent } from '../hooks/useTauri'; +import { useModalStyle } from '../hooks/useModalStyle'; + +/** + * cinny-desktop #5: the first time the window is closed, ask whether Lotus Chat + * should keep running in the tray (calls, messages, notifications) or quit — + * and, in the same moment, whether it should start when you sign in. Asked + * once; changeable in Settings → General. The native side sends + * `lotus-close-requested` only while the choice is still "ask", and never + * during a call (a call always goes to the tray). + */ +export function CloseBehaviorPrompt() { + const [open, setOpen] = useState(false); + const [launchOnLogin, setLaunchOnLogin] = useState(false); + const modalStyle = useModalStyle(420); + + // Tells the native side we're listening (see get_close_behavior). + useEffect(() => { + if (!isTauri()) return; + tauriInvoke()?.('get_close_behavior').catch(() => undefined); + }, []); + + useTauriEvent('lotus-close-requested', () => setOpen(true)); + + const choose = useCallback( + (value: 'tray' | 'quit') => { + if (launchOnLogin) invokeTauri('plugin:autostart|enable'); + setOpen(false); + invokeTauri('resolve_close_request', { value }); + }, + [launchOnLogin], + ); + + if (!open) return null; + return ( + }> + + setOpen(false), + clickOutsideDeactivates: true, + }} + > + +
+ + Keep Lotus Chat running? + +
+ + + Lotus Chat can keep running in the system tray when you close this window, so + messages, notifications and calls still reach you. Open it again from the tray icon. + + + ) => + setLaunchOnLogin(e.currentTarget.checked) + } + /> + Start Lotus Chat when I sign in to my computer + + + + + + + You can change this in Settings → General. + + +
+
+
+
+ ); +} diff --git a/src/app/features/settings/general/General.tsx b/src/app/features/settings/general/General.tsx index cfdedc137..edcb37f03 100644 --- a/src/app/features/settings/general/General.tsx +++ b/src/app/features/settings/general/General.tsx @@ -164,11 +164,18 @@ function AutostartSetting() { // [cinny-desktop #3] null until the native side answers (older builds don't // have the command, so the switch just stays hidden there). const [startMinimized, setStartMinimized] = useState(null); + // [cinny-desktop #5] "ask" | "tray" | "quit"; null on builds without it. + const [closeBehavior, setCloseBehavior] = useState(null); useEffect(() => { tauriInvoke()?.('plugin:autostart|is_enabled') .then((value) => setEnabled(value === true)) .catch(() => undefined); + tauriInvoke()?.('get_close_behavior') + .then((value) => { + if (typeof value === 'string') setCloseBehavior(value); + }) + .catch(() => undefined); tauriInvoke()?.('get_start_minimized') .then((value) => { if (typeof value === 'boolean') setStartMinimized(value); @@ -181,6 +188,11 @@ function AutostartSetting() { setEnabled(value); }; + const handleCloseBehavior = (value: string) => { + invokeTauri('set_close_behavior', { value }); + setCloseBehavior(value); + }; + const handleStartMinimized = (value: boolean) => { invokeTauri('set_start_minimized', { value }); setStartMinimized(value); @@ -194,6 +206,24 @@ function AutostartSetting() { description="Start Lotus Chat automatically when you sign in to your computer." after={} /> + {closeBehavior !== null && ( + + } + /> + )} {enabled && startMinimized !== null && ( +