import { useState } from 'react'; import { Gauge, Radio, ChevronDown } from 'lucide-react'; import { cn } from '@/lib/utils'; import { MeterBar } from '@/components/MeterBar'; import type { TGStatus, TGChannel } from '@/components/TunerGeniusPanel'; import { TunerGeniusAutotune, TunerGeniusSetBypass, TunerGeniusSetOperate, TunerGeniusActivate } from '../../wailsjs/go/main/App'; // TunerCard renders the 4O3A Tuner Genius XL exactly like the amplifier card // (AmpCard) so Station Control and the FlexRadio panel show the SAME card. It // mirrors the native app's two channels (A / B) with their source, frequency and // antenna, a live PWR / SWR pair, and the Tune / Bypass / Operate actions. It // drives the backend directly (no local state) — the caller's ~1.5s poll // reconciles the display, just like AmpCard. Meters come from the shared MeterBar // so they're the exact same size as the Flex/amp meters. function Card({ icon: Icon, title, accent, children, ckey }: { icon: any; title: string; accent?: string; children: React.ReactNode; ckey?: string }) { // Collapsible with persisted state — same behaviour as the FlexRadio panel's Card. const storeKey = 'opslog.cardOpen.' + (ckey || title); const [open, setOpen] = useState(() => localStorage.getItem(storeKey) !== '0'); const toggle = () => setOpen((o) => { const n = !o; localStorage.setItem(storeKey, n ? '1' : '0'); return n; }); return (
{open &&
{children}
}
); } // ChannelButton — one of the two RF channels (A / B). Clicking it makes that // channel active. Shows the source (RF Sense / Flex / CAT…), frequency and // antenna, matching the two rows of the native 4O3A app. function ChannelButton({ letter, ch, active, ptt, threeWay, onSelect, t }: { letter: 'A' | 'B'; ch: TGChannel; active: boolean; ptt: boolean; threeWay: boolean; onSelect: () => void; t: (k: string, v?: any) => string; }) { const cls = ptt ? 'bg-gradient-to-b from-red-500 to-rose-600 text-white border-red-400/50 shadow-[0_0_10px_rgba(244,63,94,0.5)]' : active ? 'bg-gradient-to-b from-emerald-500 to-emerald-600 text-white border-emerald-400/50 shadow-[0_0_9px_rgba(16,185,129,0.4)]' : 'bg-card text-foreground/80 border-border hover:bg-muted'; const src = ch.mode_str || '—'; const freq = ch.freq_mhz && ch.freq_mhz > 0 ? `${ch.freq_mhz.toFixed(3)} MHz` : '—'; return ( ); } export function TunerCard({ status, t }: { status: TGStatus; t: (k: string, v?: any) => string }) { const connected = !!status.connected; const vswr = status.vswr && status.vswr > 0 ? status.vswr : undefined; const fwdW = status.fwd_w && status.fwd_w >= 1 ? status.fwd_w : 0; const active = status.active ?? 1; const a: TGChannel = status.a ?? {}; const b: TGChannel = status.b ?? {}; const title = `${t('tgp.title')}${status.host ? ' · ' + status.host : ''}`; return (
{connected ? (status.bypass ? t('tgp.bypassed') : t('tgp.inLine')) : t('tgp.offline')}
{status.message && ( ⚠ {status.message} )}
{connected && ( <> {/* Channel A / B selector — click to make active (activate ch=1/2). */}
TunerGeniusActivate(1).catch(() => {})} t={t} /> TunerGeniusActivate(2).catch(() => {})} t={t} />
{/* PWR + SWR meters — same grid as the Flex/amp meters so they match size. */}
= 1 ? `${Math.round(fwdW)} W` : '—'} segColor={(f) => (f > 0.9 ? '#dc2626' : f > 0.75 ? '#f59e0b' : '#ea580c')} /> (f > 0.5 ? '#dc2626' : f > 0.25 ? '#f59e0b' : '#16a34a')} />
)} ); }