diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index b17cc00..2a4297a 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -46,7 +46,6 @@ pub struct DSP408Snapshot { pub state: types::DSPState, pub input_meters: types::InputMeters, pub output_meters: types::OutputMeters, - pub mode: types::DSPMode, } #[tauri::command] @@ -104,7 +103,6 @@ pub async fn get_dsp_snapshot( state: device.dsp.state().clone(), input_meters: device.dsp.input_meters().clone(), output_meters: device.dsp.output_meters().clone(), - mode: device.dsp.mode(), }) }) } diff --git a/src/App.tsx b/src/App.tsx index aadd01e..378ff0c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useRef } from 'react'; import './App.css'; -import { DSP, AppPage } from './types'; +import { DSP, AppPage, isConnected } from './types'; import TopBar from './components/Topbar/Topbar'; import DSPPage from './pages/DspPage/DspPage'; import AddDSPForm from './pages/AddDspPage/AddDspPage'; @@ -17,7 +17,7 @@ function App() { const [selected, setSelected] = useState(null); const [page, setPage] = useState('home'); const { notifications, notify, removeNotification, hoverNotification } = useNotifications(); - const connectedDspCount = dsps.filter((dsp) => dsp.status === 'connected').length; + const connectedDspCount = dsps.filter((dsp) => isConnected(dsp)).length; const activeDsp = dsps.find((d) => d.id === selected) ?? null; const activeInstance = activeDsp ? createDSPInstance(activeDsp, setDsps, notify) : null; diff --git a/src/components/Topbar/Topbar.tsx b/src/components/Topbar/Topbar.tsx index ea2a02b..30696b0 100644 --- a/src/components/Topbar/Topbar.tsx +++ b/src/components/Topbar/Topbar.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react'; -import { DSP, AppPage } from '../../types'; +import { DSP, AppPage, isConnected } from '../../types'; import AnimatedLogo from '../../assets/icons/AnimatedLogo'; import { PlusIcon } from '../../assets/icons/PlusIcon'; import { CrownIcon } from '../../assets/icons/CrownIcon'; @@ -36,7 +36,7 @@ function Tab({ onDisconnect: (dsp: DSP) => void; actions?: React.ReactNode; }) { - const isConnected = dsp.status === 'connected'; + const isDspConnected = isConnected(dsp); const handleTabKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { @@ -60,18 +60,26 @@ function Tab({ diff --git a/src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx b/src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx index c5a6271..391000b 100644 --- a/src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx +++ b/src/features/dsp408/components/ConnectionSection/ConnectionSection.tsx @@ -1,4 +1,4 @@ -import { DSP } from '../../../../types'; +import { DSP, isConnected } from '../../../../types'; import Button from '../../../../components/Button/Button'; import Card from '../../../../components/Card/Card'; import Led from '../../../../components/Led/Led'; @@ -15,12 +15,19 @@ function ConnectionPanel({ onDisconnect: () => void; }) { const statusLabel = - dsp.status === 'connected' + isConnected(dsp) ? 'Connected' - : dsp.status === 'connecting' + : dsp.isConnecting ? 'Connecting…' : 'Disconnected'; + console.log('ConnectionPanel render:', { + id: dsp.id, + connection: dsp.type === 'DSP408' ? dsp.state.connection : undefined, + isConnected: isConnected(dsp), + isConnecting: dsp.isConnecting, +}); + return (
@@ -35,10 +42,10 @@ function ConnectionPanel({
- + {/* */} - {statusLabel} + {/* {statusLabel} */}
@@ -64,13 +71,13 @@ function ConnectionPanel({
- {dsp.status === 'connected' ? ( + {isConnected(dsp) ? ( ) : ( - )}
diff --git a/src/features/dsp408/dsp408.ts b/src/features/dsp408/dsp408.ts index a72b8e3..3004401 100644 --- a/src/features/dsp408/dsp408.ts +++ b/src/features/dsp408/dsp408.ts @@ -12,6 +12,7 @@ import { PEQBand, InputSource, DSP408Snapshot, + DSPMode, } from './types'; import { SetDsps, NotifyFn, updateDSP, setPollingPaused } from '../../dsp/dspShared'; import { registerPollStopper } from '../../dsp/pollRegistry'; @@ -117,8 +118,8 @@ export async function create(params: { ip: params.ip, port: params.port, deviceId: params.deviceId, - mode: snapshot.mode, - status: 'disconnected', + mode: params.demo ? DSPMode.Demo: DSPMode.Normal, + isConnecting: false, pollingPaused: true, state: snapshot.state, input_meters: snapshot.input_meters, @@ -130,6 +131,7 @@ export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) { async function updateDSPState(): Promise { try { const state = await invoke('get_dsp_state', { id: dsp.id }); + updateDSP(setDsps, dsp.id, (d) => ({ ...d, state }) as DSP408); return state; @@ -143,11 +145,11 @@ export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) { async function abortLocked() { await invoke('disconnect_dsp408', { id: dsp.id }).catch(() => {}); - updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'disconnected', passwordRequired: true })); + updateDSP(setDsps, dsp.id, (d) => ({ ...d, passwordRequired: true })); } async function connectInternal(password?: string) { - updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'connecting', passwordRequired: false })); + updateDSP(setDsps, dsp.id, (d) => ({ ...d, isConnecting: true, passwordRequired: false })); try { await invoke('connect_dsp408', { id: dsp.id }); @@ -159,13 +161,10 @@ export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) { return; } - try { - await invoke('unlock_device', { id: dsp.id, password }); // adjust name/signature - } catch { - // wrong password - } + let r = await invoke('unlock_device', { id: dsp.id, password }); state = await updateDSPState(); + if (isLocked(state)) { await abortLocked(); notify('Wrong password', 'error', dsp.name); @@ -173,11 +172,11 @@ export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) { } } - updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'connected', pollingPaused: false })); + updateDSP(setDsps, dsp.id, (d) => ({ ...d, isConnecting: false, pollingPaused: false })); notify('Connected', 'success', dsp.name); startPolling(dsp, setDsps); } catch (err) { - updateDSP(setDsps, dsp.id, (d) => ({ ...d, status: 'disconnected' })); + updateDSP(setDsps, dsp.id, (d) => ({ ...d, isConnecting: false })); notify(`Connection failed: ${String(err)}`, 'error', dsp.name); } } @@ -216,7 +215,6 @@ export function forDSP408(dsp: DSP408, setDsps: SetDsps, notify: NotifyFn) { updateDSP(setDsps, dsp.id, (d) => ({ ...d, - status: 'disconnected', pollingPaused: true, })); diff --git a/src/features/dsp408/types.ts b/src/features/dsp408/types.ts index d7432b4..aea88c2 100644 --- a/src/features/dsp408/types.ts +++ b/src/features/dsp408/types.ts @@ -243,15 +243,23 @@ export type DSPState = { flags: DeviceFlags; presets: PresetBank; current_config: DSPConfigState; + connection: ConnectionStatus, }; -export type DSPMode = 'demo' | 'disconnected' | 'connected'; +export enum ConnectionStatus { + Connected, + Disconnected, +} + +export enum DSPMode { + Demo, + Normal, +} export type DSP408Snapshot = { state: DSPState; input_meters: DSP408InputMeters; output_meters: DSP408OutputMeters; - mode: DSPMode; }; export interface Meter { diff --git a/src/types.ts b/src/types.ts index 8bd41ad..3d5a8f6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,10 +3,9 @@ import { DSPMode, DSP408OutputMeters, DSP408InputMeters, + ConnectionStatus, } from './features/dsp408/types'; -export type DSPStatus = 'connected' | 'connecting' | 'disconnected'; - export type NotificationType = 'success' | 'error' | 'warning'; export type Notification = { id: number; @@ -39,12 +38,15 @@ interface DSPBase { mode: DSPMode; passwordRequired?: boolean; - - status: DSPStatus; - + isConnecting: boolean; pollingPaused: boolean; } +export function isConnected(dsp: DSP): boolean { + return dsp.type === 'DSP408' + && dsp.state.connection === ConnectionStatus.Connected; +} + export type DSP408 = DSPBase & { type: 'DSP408'; state: DSP408State;