Remove notification volume draft sync effect (#3142)

Co-authored-by: Jinwoo-H <jinwoo0825@gmail.com>
This commit is contained in:
Neil 2026-05-30 12:40:10 -07:00 committed by GitHub
parent 14be55e5b9
commit ccb21eb405
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 6 deletions

View File

@ -2,7 +2,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { renderToStaticMarkup } from 'react-dom/server'
import type { GlobalSettings, NotificationDispatchRequest } from '../../../../shared/types'
import { getNotificationSoundOptions } from '@/components/notification-sound-options'
import { NotificationsPane, sendNotificationSettingsTestNotification } from './NotificationsPane'
import {
createNotificationVolumeDraftState,
NotificationsPane,
resolveNotificationVolumeDraftState,
sendNotificationSettingsTestNotification
} from './NotificationsPane'
const { toastError, toastMessage, toastSuccess } = vi.hoisted(() => ({
toastError: vi.fn(),
@ -54,6 +59,17 @@ describe('NotificationsPane', () => {
)
})
it('resets the volume draft only when the persisted volume changes', () => {
const state = createNotificationVolumeDraftState(50)
state.draft = 75
expect(resolveNotificationVolumeDraftState(state, 50)).toBe(state)
expect(resolveNotificationVolumeDraftState(state, 25)).toEqual({
sourceVolume: 25,
draft: 25
})
})
it('uses native main-process delivery even when renderer permission is stale denied on macOS', async () => {
const notifications = {
getPermissionStatus: vi.fn(async () => ({

View File

@ -42,6 +42,29 @@ type SystemNotificationSettingsCopy = {
failureDescription: string
}
type NotificationVolumeDraftState = {
sourceVolume: number
draft: number
}
export function createNotificationVolumeDraftState(
sourceVolume: number
): NotificationVolumeDraftState {
return {
sourceVolume,
draft: sourceVolume
}
}
export function resolveNotificationVolumeDraftState(
state: NotificationVolumeDraftState,
sourceVolume: number
): NotificationVolumeDraftState {
return state.sourceVolume === sourceVolume
? state
: createNotificationVolumeDraftState(sourceVolume)
}
function getSystemNotificationSettingsCopy(
platform: NodeJS.Platform
): SystemNotificationSettingsCopy | null {
@ -161,15 +184,32 @@ export function NotificationsPane({
})
}
// Why: keep dragging local and persist only on Radix's commit event. That
// avoids IPC on every tick without a debounce timer that can race settings updates.
const [volumeDraft, setVolumeDraft] = useState(notificationSettings.customSoundVolume)
useEffect(() => {
notificationSettingsRef.current = notificationSettings
setVolumeDraft(notificationSettings.customSoundVolume)
}, [notificationSettings])
// Why: keep dragging local and persist only on Radix's commit event. That
// avoids IPC on every tick without a debounce timer that can race settings updates.
const [volumeDraftState, setVolumeDraftState] = useState(() =>
createNotificationVolumeDraftState(notificationSettings.customSoundVolume)
)
const resolvedVolumeDraftState = resolveNotificationVolumeDraftState(
volumeDraftState,
notificationSettings.customSoundVolume
)
if (resolvedVolumeDraftState !== volumeDraftState) {
// Why: external settings writes should update the slider before paint, but
// unrelated notification toggles should not restart an in-progress drag.
setVolumeDraftState(resolvedVolumeDraftState)
}
const volumeDraft = resolvedVolumeDraftState.draft
const setVolumeDraft = (value: number): void => {
setVolumeDraftState((current) => ({
...resolveNotificationVolumeDraftState(current, notificationSettings.customSoundVolume),
draft: value
}))
}
const handleVolumeCommit = (value: number): void => {
if (notificationSettingsRef.current.customSoundVolume !== value) {
void updateNotificationSettings({ customSoundVolume: value })