mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-16 01:21:20 -04:00
mobile swappy controls
This commit is contained in:
+20
-10
@@ -3,8 +3,8 @@ import TelemetryPanel from './components/TelemetryPanel.jsx';
|
||||
import ReplaySourcesPanel from './components/ReplaySourcesPanel.jsx';
|
||||
import AlertFeed from './components/AlertFeed.jsx';
|
||||
import MobileControls, {
|
||||
MobileLeftColumn,
|
||||
MobileRightColumn,
|
||||
MobileActionsColumn,
|
||||
MobileDriveColumn,
|
||||
} from './components/MobileControls.jsx';
|
||||
import {
|
||||
ControlSystemProvider,
|
||||
@@ -160,11 +160,11 @@ function MobileFeatureTabs({
|
||||
);
|
||||
}
|
||||
|
||||
function MobilePortraitLayout({ onOpenHelpOverlay }) {
|
||||
function MobilePortraitLayout({ onOpenHelpOverlay, swapMobileControlColumns = false }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<DriverVideoPanel layoutFormat="mobile-portrait" />
|
||||
<MobileControls />
|
||||
<MobileControls swapColumns={swapMobileControlColumns} />
|
||||
<div className="grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">
|
||||
<ReplaySourcesPanel panelId="replay-sources-mobile-portrait" />
|
||||
<RoverQueuesPanel />
|
||||
@@ -179,12 +179,18 @@ function MobilePortraitLayout({ onOpenHelpOverlay }) {
|
||||
);
|
||||
}
|
||||
|
||||
function MobileLandscapeLayout({ onOpenHelpOverlay }) {
|
||||
function MobileLandscapeLayout({ onOpenHelpOverlay, swapMobileControlColumns = false }) {
|
||||
const columnClass = 'self-start h-[min(100svh,32rem)]';
|
||||
const firstColumn = swapMobileControlColumns
|
||||
? <MobileDriveColumn layout="landscape" className={columnClass} />
|
||||
: <MobileActionsColumn layout="landscape" className={columnClass} />;
|
||||
const secondColumn = swapMobileControlColumns
|
||||
? <MobileActionsColumn layout="landscape" className={columnClass} />
|
||||
: <MobileDriveColumn layout="landscape" className={columnClass} />;
|
||||
return (
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<section className="grid min-h-screen grid-cols-[minmax(0,0.7fr)_minmax(0,2.1fr)_minmax(0,0.7fr)] gap-0.5">
|
||||
<MobileLeftColumn layout="landscape" className={columnClass} />
|
||||
{firstColumn}
|
||||
<div>
|
||||
<DriverVideoPanel layoutFormat="mobile-landscape" />
|
||||
<div className="grid gap-0.5 grid-cols-[minmax(0,1fr)_minmax(0,1.4fr)]">
|
||||
@@ -193,7 +199,7 @@ function MobileLandscapeLayout({ onOpenHelpOverlay }) {
|
||||
</div>
|
||||
{/* <TelemetryPanel /> */}
|
||||
</div>
|
||||
<MobileRightColumn layout="landscape" className={columnClass} />
|
||||
{secondColumn}
|
||||
</section>
|
||||
<div className="flex flex-col gap-0.5 pb-0">
|
||||
<MobileFeatureTabs
|
||||
@@ -234,6 +240,10 @@ function AppWithProviders({ layout, isDesktop, fullscreen }) {
|
||||
status: helpStatus,
|
||||
save: saveHelpSettings,
|
||||
} = useSettingsNamespace('help', { showOnLoad: true });
|
||||
const { value: pageSettings } = useSettingsNamespace('page', {
|
||||
swapMobileControlColumns: false,
|
||||
});
|
||||
const swapMobileControlColumns = Boolean(pageSettings?.swapMobileControlColumns);
|
||||
const [helpVisible, setHelpVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -260,9 +270,9 @@ function AppWithProviders({ layout, isDesktop, fullscreen }) {
|
||||
isDesktop
|
||||
? <DesktopLayout layout={layout} onOpenHelpOverlay={openHelp} />
|
||||
: layout === 'mobile-landscape'
|
||||
? <MobileLandscapeLayout onOpenHelpOverlay={openHelp} />
|
||||
: <MobilePortraitLayout onOpenHelpOverlay={openHelp} />,
|
||||
[isDesktop, layout, openHelp],
|
||||
? <MobileLandscapeLayout onOpenHelpOverlay={openHelp} swapMobileControlColumns={swapMobileControlColumns} />
|
||||
: <MobilePortraitLayout onOpenHelpOverlay={openHelp} swapMobileControlColumns={swapMobileControlColumns} />,
|
||||
[isDesktop, layout, openHelp, swapMobileControlColumns],
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -224,7 +224,7 @@ function MobileAuxButton({ id, label, values, color, disabled, onPress, onReleas
|
||||
);
|
||||
}
|
||||
|
||||
function MobileLeftColumnContent({ layout }) {
|
||||
function MobileActionsColumnContent({ layout }) {
|
||||
const {
|
||||
state: { roverId, camera, horn },
|
||||
pipeline,
|
||||
@@ -347,15 +347,15 @@ function MobileLeftColumnContent({ layout }) {
|
||||
);
|
||||
}
|
||||
|
||||
export function MobileLeftColumn({ layout, className = '' }) {
|
||||
export function MobileActionsColumn({ layout, className = '' }) {
|
||||
return (
|
||||
<div className={`flex flex-col gap-0.5 ${className}`.trim()}>
|
||||
<MobileLeftColumnContent layout={layout} />
|
||||
<MobileActionsColumnContent layout={layout} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function MobileRightColumn({ layout, className = '' }) {
|
||||
export function MobileDriveColumn({ layout, className = '' }) {
|
||||
return (
|
||||
<div className={`flex flex-col gap-0.5 ${className}`.trim()}>
|
||||
<MobileJoystickPanel layout={layout === 'landscape' ? 'landscape' : 'portrait'} />
|
||||
@@ -363,13 +363,19 @@ export function MobileRightColumn({ layout, className = '' }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function MobilePortraitControls() {
|
||||
export default function MobilePortraitControls({ swapColumns = false }) {
|
||||
const columnHeight = 'h-[min(60svh,24rem)]';
|
||||
const firstColumn = swapColumns
|
||||
? <MobileDriveColumn layout="portrait" className={columnHeight} />
|
||||
: <MobileActionsColumn layout="portrait" className={columnHeight} />;
|
||||
const secondColumn = swapColumns
|
||||
? <MobileActionsColumn layout="portrait" className={columnHeight} />
|
||||
: <MobileDriveColumn layout="portrait" className={columnHeight} />;
|
||||
return (
|
||||
<section className="panel">
|
||||
<div className="grid grid-cols-2 gap-0.5 items-stretch">
|
||||
<MobileLeftColumn layout="portrait" className={columnHeight} />
|
||||
<MobileRightColumn layout="portrait" className={columnHeight} />
|
||||
{firstColumn}
|
||||
{secondColumn}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -32,9 +32,11 @@ export default function SettingsPanel() {
|
||||
const { value: pageSettings, save: savePageSettings } = useSettingsNamespace('page', {
|
||||
hudMapDesktop: false,
|
||||
connectionTransport: 'websocket',
|
||||
swapMobileControlColumns: false,
|
||||
});
|
||||
const { value: audioSettings, save: saveAudioSettings } = useSettingsNamespace('audio', AUDIO_SETTINGS_DEFAULTS);
|
||||
const connectionTransport = pageSettings?.connectionTransport || 'websocket';
|
||||
const swapMobileControlColumns = Boolean(pageSettings?.swapMobileControlColumns);
|
||||
const masterVolume = Number.isFinite(audioSettings?.masterVolume) ? audioSettings.masterVolume : AUDIO_SETTINGS_DEFAULTS.masterVolume;
|
||||
const alertVolume = Number.isFinite(audioSettings?.alertVolume) ? audioSettings.alertVolume : AUDIO_SETTINGS_DEFAULTS.alertVolume;
|
||||
const roverVolume = Number.isFinite(audioSettings?.roverVolume) ? audioSettings.roverVolume : AUDIO_SETTINGS_DEFAULTS.roverVolume;
|
||||
@@ -80,6 +82,11 @@ export default function SettingsPanel() {
|
||||
const checked = Boolean(event.target.checked);
|
||||
saveAudioSettings((current) => ({ ...(current ?? {}), mainBrushDuckEnabled: checked }));
|
||||
};
|
||||
|
||||
const handleSwapMobileControlColumns = (event) => {
|
||||
const checked = Boolean(event.target.checked);
|
||||
savePageSettings((current) => ({ ...(current ?? {}), swapMobileControlColumns: checked }));
|
||||
};
|
||||
return (
|
||||
<Tabs defaultTab="keybindings">
|
||||
<TabList>
|
||||
@@ -114,6 +121,18 @@ export default function SettingsPanel() {
|
||||
</label>
|
||||
<p className="text-xs text-slate-500">Mobile HUD keeps the map on by default.</p>
|
||||
</section>
|
||||
<section className="panel-section space-y-0.5 text-sm">
|
||||
<p className="text-slate-400">Mobile controls</p>
|
||||
<label className="flex items-center gap-0.5 text-slate-200">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="accent-emerald-500"
|
||||
checked={swapMobileControlColumns}
|
||||
onChange={handleSwapMobileControlColumns}
|
||||
/>
|
||||
<span>Swap control columns (put joystick on the left)</span>
|
||||
</label>
|
||||
</section>
|
||||
<section className="panel-section space-y-0.5 text-sm">
|
||||
<p className="text-slate-400">Audio</p>
|
||||
<label className="grid gap-0.5 text-slate-200">
|
||||
|
||||
@@ -124,7 +124,7 @@ export const HELP_CONTENT = {
|
||||
title: 'Driving the rover',
|
||||
items: [
|
||||
{ segments: ['Press the "Start Driving" button onscreen to put the rover into driving mode.'] },
|
||||
'Look below the rover video. Use the joystick on the right to move the rover, and hold the buttons on the left to run the aux motors.'
|
||||
'Look below the rover video. Use the joystick column to move the rover, and hold the aux buttons in the other control column.'
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -154,7 +154,7 @@ export const HELP_CONTENT = {
|
||||
title: 'Driving the rover',
|
||||
items: [
|
||||
{ segments: ['Press the "Start Driving" button, or the "Drive" button to put the rover into driving mode.'] },
|
||||
'Use the joystick to the right of the video feed to move the rover, and hold the buttons on the left to run the aux motors.'
|
||||
'Use the joystick column beside the video feed to move the rover, and hold the aux buttons in the other control column.'
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user