mirror of
https://github.com/Boof2015/prism.git
synced 2026-08-18 19:44:16 +02:00
tray icon and open on login
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import { useEffect, type JSX } from 'react'
|
||||
import type { TrayRendererCommand, TrayRendererState } from '../../types/desktopIntegration'
|
||||
import { useAudioStore } from '../stores/audioStore'
|
||||
import { useSettingsStore } from '../stores/settingsStore'
|
||||
import { useUiStore } from '../stores/uiStore'
|
||||
|
||||
interface TrayControlBridgeProps {
|
||||
ready: boolean
|
||||
}
|
||||
|
||||
const DEFAULT_SYSTEM_SOURCE_ID = '__default_system_output__'
|
||||
|
||||
function getErrorMessage(error: unknown, fallback: string): string {
|
||||
return error instanceof Error && error.message ? error.message : fallback
|
||||
}
|
||||
|
||||
async function handleTrayCommand(command: TrayRendererCommand): Promise<void> {
|
||||
if (command.type === 'open-settings') {
|
||||
useUiStore.getState().setSettingsOpen(true)
|
||||
return
|
||||
}
|
||||
|
||||
if (command.type === 'load-profile') {
|
||||
const settings = useSettingsStore.getState()
|
||||
try {
|
||||
await settings.guardProfileTransition(async () => {
|
||||
await useSettingsStore.getState().loadProfile(command.profileId)
|
||||
})
|
||||
} catch (error) {
|
||||
useUiStore.getState().showBanner({
|
||||
tone: 'error',
|
||||
message: getErrorMessage(error, 'Could not load the profile.'),
|
||||
actions: [],
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const audio = useAudioStore.getState()
|
||||
if (command.type === 'select-system-source') {
|
||||
await audio.selectSystemSource(command.sourceId)
|
||||
await useAudioStore.getState().startCapture()
|
||||
return
|
||||
}
|
||||
if (command.type === 'select-input-source') {
|
||||
await audio.selectDevice(command.deviceId)
|
||||
await useAudioStore.getState().startCapture()
|
||||
return
|
||||
}
|
||||
if (command.type === 'set-capture-running') {
|
||||
if (command.running) {
|
||||
await audio.startCapture()
|
||||
} else {
|
||||
audio.stopCapture()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function TrayControlBridge({ ready }: TrayControlBridgeProps): JSX.Element | null {
|
||||
const profiles = useSettingsStore((state) => state.profiles)
|
||||
const activeProfileId = useSettingsStore((state) => state.activeProfileId)
|
||||
const hasUnsavedProfileChanges = useSettingsStore((state) => state.hasUnsavedProfileChanges)
|
||||
const captureStatus = useAudioStore((state) => state.captureStatus)
|
||||
const activeSourceLabel = useAudioStore((state) => state.activeSourceLabel)
|
||||
const captureMode = useAudioStore((state) => state.captureMode)
|
||||
const selectedSystemSourceId = useAudioStore((state) => state.selectedSystemSourceId)
|
||||
const selectedDeviceId = useAudioStore((state) => state.selectedDeviceId)
|
||||
const systemSources = useAudioStore((state) => state.systemSources)
|
||||
const devices = useAudioStore((state) => state.devices)
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribe = window.electronAPI.trayControls.onCommand((command) => {
|
||||
void handleTrayCommand(command).catch((error) => {
|
||||
useUiStore.getState().showBanner({
|
||||
tone: 'error',
|
||||
message: getErrorMessage(error, 'The tray action could not be completed.'),
|
||||
actions: [],
|
||||
})
|
||||
})
|
||||
})
|
||||
return unsubscribe
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!ready) {
|
||||
window.electronAPI.trayControls.markNotReady()
|
||||
return
|
||||
}
|
||||
window.electronAPI.trayControls.markReady()
|
||||
return () => window.electronAPI.trayControls.markNotReady()
|
||||
}, [ready])
|
||||
|
||||
useEffect(() => {
|
||||
const visibleSystemSources = systemSources.length > 0
|
||||
? systemSources
|
||||
: [{ id: DEFAULT_SYSTEM_SOURCE_ID, label: 'Default Output', isDefault: true }]
|
||||
const state: TrayRendererState = {
|
||||
profiles: Object.entries(profiles).map(([id, profile]) => ({ id, name: profile.name })),
|
||||
activeProfileId,
|
||||
hasUnsavedProfileChanges,
|
||||
captureStatus,
|
||||
activeSourceLabel,
|
||||
captureMode,
|
||||
selectedSystemSourceId,
|
||||
selectedDeviceId,
|
||||
systemSources: visibleSystemSources.map((source) => ({
|
||||
id: source.id,
|
||||
label: source.label,
|
||||
isDefault: source.isDefault,
|
||||
})),
|
||||
inputSources: [
|
||||
{ id: '', label: 'Default Input', isDefault: true },
|
||||
...devices
|
||||
.filter((device) => device.deviceId !== 'default')
|
||||
.map((device) => ({
|
||||
id: device.deviceId,
|
||||
label: device.label || `Input ${device.deviceId.slice(0, 8)}`,
|
||||
})),
|
||||
],
|
||||
}
|
||||
window.electronAPI.trayControls.publishState(state)
|
||||
}, [
|
||||
activeProfileId,
|
||||
activeSourceLabel,
|
||||
captureMode,
|
||||
captureStatus,
|
||||
devices,
|
||||
hasUnsavedProfileChanges,
|
||||
profiles,
|
||||
selectedDeviceId,
|
||||
selectedSystemSourceId,
|
||||
systemSources,
|
||||
])
|
||||
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user