feat: added FlexRadio support (meters & basic functions)

This commit is contained in:
2026-06-17 18:29:35 +02:00
parent abdab22010
commit bde1195b34
9 changed files with 1808 additions and 13 deletions
+11 -6
View File
@@ -138,6 +138,7 @@ interface Props {
onClose: () => void;
onSaved: () => void;
onMainPaneChanged?: (side: 'left' | 'right', value: string) => void; // live Main-view layout update
flexAvailable?: boolean; // CAT backend is FlexRadio → offer it as a Main pane
}
// Pretty little card showing what OpsLog will stamp on each QSO based on
@@ -457,11 +458,15 @@ const MAIN_PANE_OPTIONS: { value: string; label: string }[] = [
{ value: 'cluster', label: 'Cluster spots' },
{ value: 'worked', label: 'Worked before' },
];
function MainViewPanes({ onChanged }: { onChanged?: (side: 'left' | 'right', value: string) => void }) {
function MainViewPanes({ onChanged, flexAvailable }: { onChanged?: (side: 'left' | 'right', value: string) => void; flexAvailable?: boolean }) {
const [left, setLeft] = useState('map1');
const [right, setRight] = useState('map2');
// FlexRadio is only offered when the CAT backend is a Flex.
const options = flexAvailable
? [...MAIN_PANE_OPTIONS, { value: 'flex', label: 'FlexRadio controls' }]
: MAIN_PANE_OPTIONS;
useEffect(() => {
const valid = (v: string) => MAIN_PANE_OPTIONS.some((o) => o.value === v);
const valid = (v: string) => v === 'flex' || MAIN_PANE_OPTIONS.some((o) => o.value === v);
Promise.all([GetUIPref('mainPaneLeft').catch(() => ''), GetUIPref('mainPaneRight').catch(() => '')])
.then(([l, r]) => { if (valid(l)) setLeft(l); if (valid(r)) setRight(r); });
}, []);
@@ -482,7 +487,7 @@ function MainViewPanes({ onChanged }: { onChanged?: (side: 'left' | 'right', val
<Select value={left} onValueChange={(v) => pick('left', v)}>
<SelectTrigger className="h-8 text-xs"><SelectValue /></SelectTrigger>
<SelectContent>
{MAIN_PANE_OPTIONS.map((o) => <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>)}
{options.map((o) => <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>)}
</SelectContent>
</Select>
</label>
@@ -491,7 +496,7 @@ function MainViewPanes({ onChanged }: { onChanged?: (side: 'left' | 'right', val
<Select value={right} onValueChange={(v) => pick('right', v)}>
<SelectTrigger className="h-8 text-xs"><SelectValue /></SelectTrigger>
<SelectContent>
{MAIN_PANE_OPTIONS.map((o) => <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>)}
{options.map((o) => <SelectItem key={o.value} value={o.value}>{o.label}</SelectItem>)}
</SelectContent>
</Select>
</label>
@@ -550,7 +555,7 @@ function ComingSoon({ id, icon: Icon }: { id: SectionId; icon?: any }) {
);
}
export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChanged }: Props) {
export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChanged, flexAvailable }: Props) {
const [selected, setSelected] = useState<SectionId>((initialSection as SectionId) || 'station');
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
@@ -3347,7 +3352,7 @@ export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChan
</label>
<TelemetryToggle />
<MainViewPanes onChanged={onMainPaneChanged} />
<MainViewPanes onChanged={onMainPaneChanged} flexAvailable={flexAvailable} />
<div className="border-t border-border/60 pt-4 space-y-2">
<h4 className="text-sm font-semibold text-foreground">Password encryption</h4>