feat: Mainview can choose Map, cluster or worked before

This commit is contained in:
2026-06-16 21:04:19 +02:00
parent 3d15f20c7f
commit a7bbc53c35
4 changed files with 477 additions and 317 deletions
+58 -1
View File
@@ -34,6 +34,7 @@ import {
GetPOTAToken, SavePOTAToken,
TestLoTWUpload, ListTQSLStationLocations,
ComputeStationInfo,
GetUIPref, SetUIPref,
} from '../../wailsjs/go/main/App';
import type { profile as profileModels } from '../../wailsjs/go/models';
import type { LookupSettingsForm, StationSettingsForm, ListsSettingsForm, ModePresetForm } from '@/types';
@@ -136,6 +137,7 @@ interface Props {
initialSection?: string;
onClose: () => void;
onSaved: () => void;
onMainPaneChanged?: (side: 'left' | 'right', value: string) => void; // live Main-view layout update
}
// Pretty little card showing what OpsLog will stamp on each QSO based on
@@ -445,6 +447,59 @@ function TelemetryToggle() {
);
}
// MainViewPanes lets the operator choose what the Main tab's left and right
// panes show, independently: the great-circle map, the locator street map, the
// cluster grid or the worked-before grid. Per-profile (stored via SetUIPref,
// which is profile-prefixed). Self-contained so it owns its async-loaded state.
const MAIN_PANE_OPTIONS: { value: string; label: string }[] = [
{ value: 'map1', label: 'Map — great-circle + beam' },
{ value: 'map2', label: 'Map — locator (street)' },
{ value: 'cluster', label: 'Cluster spots' },
{ value: 'worked', label: 'Worked before' },
];
function MainViewPanes({ onChanged }: { onChanged?: (side: 'left' | 'right', value: string) => void }) {
const [left, setLeft] = useState('map1');
const [right, setRight] = useState('map2');
useEffect(() => {
const valid = (v: string) => 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); });
}, []);
const pick = (side: 'left' | 'right', v: string) => {
if (side === 'left') setLeft(v); else setRight(v);
// Persist (per-profile) AND tell the parent the new value directly, so the
// Main view updates from the chosen value — never a stale DB re-read.
SetUIPref(side === 'left' ? 'mainPaneLeft' : 'mainPaneRight', v).catch(() => {});
onChanged?.(side, v);
};
return (
<div className="border-t border-border/60 pt-4 space-y-2">
<h4 className="text-sm font-semibold text-foreground">Main view</h4>
<p className="text-xs text-muted-foreground">Choose what the Main tab shows on each side (per profile).</p>
<div className="grid grid-cols-2 gap-3 max-w-xl">
<label className="flex flex-col gap-1 text-xs">
<span className="text-muted-foreground">Left pane</span>
<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>)}
</SelectContent>
</Select>
</label>
<label className="flex flex-col gap-1 text-xs">
<span className="text-muted-foreground">Right pane</span>
<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>)}
</SelectContent>
</Select>
</label>
</div>
</div>
);
}
// FlexDiscover scans the LAN for FlexRadio broadcasts and lets the user pick one
// (fills the IP/port). Self-contained so it can own its state (rendered inside
// the hook-less CATPanel).
@@ -495,7 +550,7 @@ function ComingSoon({ id, icon: Icon }: { id: SectionId; icon?: any }) {
);
}
export function SettingsModal({ onClose, onSaved, initialSection }: Props) {
export function SettingsModal({ onClose, onSaved, initialSection, onMainPaneChanged }: Props) {
const [selected, setSelected] = useState<SectionId>((initialSection as SectionId) || 'station');
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
@@ -3292,6 +3347,8 @@ export function SettingsModal({ onClose, onSaved, initialSection }: Props) {
</label>
<TelemetryToggle />
<MainViewPanes onChanged={onMainPaneChanged} />
<div className="border-t border-border/60 pt-4 space-y-2">
<h4 className="text-sm font-semibold text-foreground">Password encryption</h4>
{secret.has_passphrase ? (