feat(icom): a speaker toggle on the console itself
Muting the network RX audio took a trip through Settings → Audio → Stop listening — two panels away from the console the operator is actually using. A speaker button now sits beside ON/OFF (network only, like them): one click to listen or mute, the recorder and the voice keyer unaffected, the choice remembered across reconnects and launches.
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { Radio, AudioLines, Mic, Activity, SlidersHorizontal, Antenna, Filter, Power } from 'lucide-react';
|
||||
import { Radio, AudioLines, Mic, Activity, SlidersHorizontal, Antenna, Filter, Power, Volume2, VolumeX } from 'lucide-react';
|
||||
import {
|
||||
GetIcomState, IcomRefresh,
|
||||
IcomSetAFGain, IcomSetRFGain, IcomSetNB, IcomSetNBLevel, IcomSetNR, IcomSetNRLevel,
|
||||
IcomSetANF, IcomSetAPF, IcomSetAGC, IcomSetPreamp, IcomSetAtt, IcomSetFilter,
|
||||
AudioMonitorActive, AudioStartMonitor, AudioStopMonitor,
|
||||
IcomSetRFPower, IcomSetMicGain, IcomSetSplit, IcomTune, IcomSetPTT,
|
||||
IcomSetScope, IcomScopeData, IcomSetScopeMode, IcomSetScopeEdges, GetCATState, SetCATFrequency, SetCATMode,
|
||||
IcomSetRIT, IcomSetRITOn, IcomSetXITOn,
|
||||
@@ -596,6 +597,23 @@ function ScopePanadapter() {
|
||||
// read every cache cycle; DSP set-controls are optimistic and reconcile on the
|
||||
// next poll. Front-panel knob changes for DSP show after ↻ Refresh.
|
||||
export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (rst: string) => void; isNetwork?: boolean } = {}) {
|
||||
// The speaker toggle lives HERE, next to ON/OFF, because that is where the
|
||||
// operator is looking — burying "stop listening" behind Settings → Audio
|
||||
// meant a trip through two panels to mute a radio sitting in the same room.
|
||||
const [listening, setListening] = useState(false);
|
||||
useEffect(() => {
|
||||
if (!isNetwork) return;
|
||||
let alive = true;
|
||||
const ask = () => AudioMonitorActive().then((v) => { if (alive) setListening(!!v); }).catch(() => {});
|
||||
ask();
|
||||
const id = window.setInterval(ask, 2000);
|
||||
return () => { alive = false; window.clearInterval(id); };
|
||||
}, [isNetwork]);
|
||||
const toggleListening = () => {
|
||||
const next = !listening;
|
||||
setListening(next);
|
||||
(next ? AudioStartMonitor() : Promise.resolve(AudioStopMonitor())).catch(() => setListening(!next));
|
||||
};
|
||||
const { t } = useI18n();
|
||||
const [st, setSt] = useState<IcomState>(ZERO);
|
||||
const [cat, setCat] = useState<any>(null); // RigState (freq/mode/split) for the VFO display
|
||||
@@ -704,6 +722,14 @@ export function IcomPanel({ onReportRST, isNetwork = false }: { onReportRST?: (r
|
||||
rig's LAN server stays alive in standby, so both work. */}
|
||||
{isNetwork && (
|
||||
<>
|
||||
<button type="button" onClick={toggleListening}
|
||||
title={listening ? t('icmp.speakerOffHint') : t('icmp.speakerOnHint')}
|
||||
className={cn('inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs font-bold',
|
||||
listening
|
||||
? 'border-primary/60 bg-primary/10 text-primary hover:bg-primary/20'
|
||||
: 'border-border bg-card text-muted-foreground hover:bg-muted')}>
|
||||
{listening ? <Volume2 className="size-3.5" /> : <VolumeX className="size-3.5" />}
|
||||
</button>
|
||||
<button type="button" onClick={() => IcomSetPower(true).catch(() => {})} title={t('icmp.powerOnHint')}
|
||||
className="inline-flex items-center gap-1 rounded-md border border-success/60 bg-success/10 px-2 py-1 text-xs font-bold text-success hover:bg-success/20">
|
||||
<Power className="size-3.5" /> ON
|
||||
|
||||
Reference in New Issue
Block a user