feat: Mainview can choose Map, cluster or worked before
This commit is contained in:
@@ -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 ? (
|
||||
|
||||
Reference in New Issue
Block a user