feat(desktop): tray Do-Not-Disturb + Launch-on-login toggle (P6-1 web)

- useTauriDnd + manualDndAtom: the native tray "Do Not Disturb" toggle
  (lotus-dnd-changed event) OR's into the notification quiet-gate in
  ClientNonUIFeatures (both invite + message notifiers), alongside Focus Assist.
- AutostartSetting in Settings → General (desktop-only): reads/sets
  plugin:autostart via invoke. Mirrors the window-chrome setting.
- Docs: LOTUS_FEATURES desktop section (Linux parity + DND + autostart),
  LOTUS_TODO P6-1 → [~], LOTUS_BUGS verification row.

Gates: tsc/eslint/prettier clean, build OK, 661 tests. Native side committed on
cinny-desktop:main (CI-compile-pending).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 13:31:09 -04:00
parent 625f0c2386
commit 804caa5130
8 changed files with 120 additions and 31 deletions
+11 -2
View File
@@ -10,6 +10,7 @@ import {
ThreadEvent,
} from 'matrix-js-sdk';
import { focusAssistActiveAtom } from '../../state/focusAssist';
import { manualDndAtom } from '../../state/manualDnd';
import { roomToUnreadAtom, unreadEqual, unreadInfoToUnread } from '../../state/room/roomToUnread';
import LogoSVG from '../../../../public/res/lotus.png';
import LogoUnreadSVG from '../../../../public/res/lotus-unread.png';
@@ -128,6 +129,7 @@ function InviteNotifications() {
const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
const [quietHoursEnabled] = useSetting(settingsAtom, 'quietHoursEnabled');
const focusAssistActive = useAtomValue(focusAssistActiveAtom);
const manualDnd = useAtomValue(manualDndAtom);
const [quietHoursStart] = useSetting(settingsAtom, 'quietHoursStart');
const [quietHoursEnd] = useSetting(settingsAtom, 'quietHoursEnd');
const [inviteSoundId] = useSetting(settingsAtom, 'inviteSoundId');
@@ -187,7 +189,9 @@ function InviteNotifications() {
useEffect(() => {
if (invites.length > perviousInviteLen && mx.getSyncState() === 'SYNCING') {
const quietActive =
focusAssistActive || (quietHoursEnabled && isInQuietHours(quietHoursStart, quietHoursEnd));
focusAssistActive ||
manualDnd ||
(quietHoursEnabled && isInQuietHours(quietHoursStart, quietHoursEnd));
if (!quietActive) {
if (showNotifications && notificationPermission('granted')) {
notify(invites.length - perviousInviteLen);
@@ -210,6 +214,7 @@ function InviteNotifications() {
quietHoursStart,
quietHoursEnd,
focusAssistActive,
manualDnd,
inviteSoundId,
]);
@@ -236,6 +241,7 @@ function MessageNotifications() {
const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
const [quietHoursEnabled] = useSetting(settingsAtom, 'quietHoursEnabled');
const focusAssistActive = useAtomValue(focusAssistActiveAtom);
const manualDnd = useAtomValue(manualDndAtom);
const [quietHoursStart] = useSetting(settingsAtom, 'quietHoursStart');
const [quietHoursEnd] = useSetting(settingsAtom, 'quietHoursEnd');
const [messageSoundId] = useSetting(settingsAtom, 'messageSoundId');
@@ -374,7 +380,9 @@ function MessageNotifications() {
}
const quietActive =
focusAssistActive || (quietHoursEnabled && isInQuietHours(quietHoursStart, quietHoursEnd));
focusAssistActive ||
manualDnd ||
(quietHoursEnabled && isInQuietHours(quietHoursStart, quietHoursEnd));
if (quietActive) return;
if (showNotifications && notificationPermission('granted')) {
@@ -409,6 +417,7 @@ function MessageNotifications() {
quietHoursStart,
quietHoursEnd,
focusAssistActive,
manualDnd,
messageSoundId,
],
);