mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
mobile controls fixes
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
# FIXED!
|
||||
# Issue 007: Timers and Polling Cleanup
|
||||
|
||||
## Summary
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,13 +6,13 @@
|
||||
<link rel="apple-touch-icon" href="/bitmap.png" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<!-- Mobile driving uses dense press controls, so the viewport opts out of browser zoom gestures that can steal touches from the controls. -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#020617" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="Roomba Rover" />
|
||||
<title>Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-CCuQOOMm.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-Df0ksHL_.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BVKa8Zph.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
1. # FIX ALL OF THE PERFORMANCE PROFILED ISSUES!!
|
||||
2. fix up ALL discord admin commands
|
||||
1. fix up ALL discord admin commands
|
||||
1. make sure all permissions are correct
|
||||
2. fuzzy search all the things
|
||||
3. dont break on multi word nicknames
|
||||
4. make all rs commands work form both the site chat and discord
|
||||
1. make sure all the permissions are correct
|
||||
2. make alert feed.jsx show more alerts at once
|
||||
3. Overseer personality swapping.
|
||||
4. maybe make a better joystick for mobile
|
||||
5. make google tts the default everywhere but roverd
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<link rel="apple-touch-icon" href="/bitmap.png" />
|
||||
<link rel="manifest" href="/manifest.json" />
|
||||
<!-- Mobile driving uses dense press controls, so the viewport opts out of browser zoom gestures that can steal touches from the controls. -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta name="theme-color" content="#020617" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
|
||||
@@ -33,6 +33,7 @@ export default function HornControl({
|
||||
);
|
||||
const [waveform, setWaveform] = useState(hornSettings?.waveform || HORN_SETTINGS_DEFAULTS.waveform);
|
||||
const settingsRootRef = useRef(null);
|
||||
const activePointerIdRef = useRef(null);
|
||||
const [freqs, setFreqs] = useState(() => {
|
||||
const base = Array.isArray(hornSettings?.freqs) ? hornSettings.freqs : HORN_SETTINGS_DEFAULTS.freqs;
|
||||
return [...base, 0, 0, 0, 0].slice(0, 4).map((f) => clampFreq(f));
|
||||
@@ -129,16 +130,39 @@ export default function HornControl({
|
||||
|
||||
const handlePointerDown = (event) => {
|
||||
if (disabled) return;
|
||||
if (activePointerIdRef.current !== null) return;
|
||||
const tag = event.target?.tagName?.toLowerCase();
|
||||
if (tag === 'input' || tag === 'select' || tag === 'option' || tag === 'label' || tag === 'button') return;
|
||||
|
||||
/*
|
||||
Horn is a hold control, so it should claim exactly the finger that started
|
||||
it. Capturing that pointer prevents tiny mobile finger drift or nearby
|
||||
controls from making the horn feel delayed or randomly interrupted.
|
||||
*/
|
||||
event.preventDefault();
|
||||
activePointerIdRef.current = event.pointerId;
|
||||
event.currentTarget.setPointerCapture?.(event.pointerId);
|
||||
start();
|
||||
};
|
||||
|
||||
const handlePointerUp = (event) => {
|
||||
if (activePointerIdRef.current !== event.pointerId) return;
|
||||
const tag = event.target?.tagName?.toLowerCase();
|
||||
if (tag === 'input' || tag === 'select' || tag === 'option' || tag === 'label' || tag === 'button') return;
|
||||
event.preventDefault();
|
||||
activePointerIdRef.current = null;
|
||||
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
||||
stop();
|
||||
};
|
||||
|
||||
const handlePointerCancel = (event) => {
|
||||
if (activePointerIdRef.current !== event.pointerId) return;
|
||||
activePointerIdRef.current = null;
|
||||
stop();
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
activePointerIdRef.current = null;
|
||||
stop();
|
||||
};
|
||||
|
||||
@@ -164,10 +188,15 @@ export default function HornControl({
|
||||
aria-pressed={pressed}
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerUp={handlePointerUp}
|
||||
onPointerLeave={stop}
|
||||
onPointerCancel={stop}
|
||||
onPointerCancel={handlePointerCancel}
|
||||
onLostPointerCapture={(event) => {
|
||||
if (activePointerIdRef.current === event.pointerId) {
|
||||
activePointerIdRef.current = null;
|
||||
stop();
|
||||
}
|
||||
}}
|
||||
onContextMenu={(event) => event.preventDefault()}
|
||||
onBlur={stop}
|
||||
onBlur={handleBlur}
|
||||
className={buttonClasses}
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -19,6 +19,7 @@ export default function NightVisionControl({
|
||||
isBoolean(nightVisionOn) ? nightVisionOn : null,
|
||||
);
|
||||
const suppressClickRef = useRef(false);
|
||||
const suppressClickTimerRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isBoolean(nightVisionOn)) {
|
||||
@@ -26,6 +27,15 @@ export default function NightVisionControl({
|
||||
}
|
||||
}, [nightVisionOn]);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (suppressClickTimerRef.current) {
|
||||
clearTimeout(suppressClickTimerRef.current);
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const hasState = isBoolean(optimistic);
|
||||
const displayOn = hasState ? optimistic : false;
|
||||
const statusLabel = hasState ? (displayOn ? 'On' : 'Off') : '—';
|
||||
@@ -52,15 +62,29 @@ export default function NightVisionControl({
|
||||
*/
|
||||
event.preventDefault();
|
||||
suppressClickRef.current = true;
|
||||
handleToggle();
|
||||
window.setTimeout(() => {
|
||||
if (suppressClickTimerRef.current) {
|
||||
clearTimeout(suppressClickTimerRef.current);
|
||||
}
|
||||
/*
|
||||
The next click normally clears this flag, but Safari may suppress the click
|
||||
completely after preventDefault(). The timer prevents a stale touch flag
|
||||
from swallowing a later keyboard or desktop click.
|
||||
*/
|
||||
suppressClickTimerRef.current = window.setTimeout(() => {
|
||||
suppressClickRef.current = false;
|
||||
}, 0);
|
||||
suppressClickTimerRef.current = null;
|
||||
}, 800);
|
||||
handleToggle();
|
||||
};
|
||||
|
||||
const handleClick = (event) => {
|
||||
if (suppressClickRef.current) {
|
||||
event.preventDefault();
|
||||
suppressClickRef.current = false;
|
||||
if (suppressClickTimerRef.current) {
|
||||
clearTimeout(suppressClickTimerRef.current);
|
||||
suppressClickTimerRef.current = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
handleToggle();
|
||||
|
||||
@@ -473,7 +473,7 @@ export function ControlSystemProvider({ children }) {
|
||||
(nightVisionOn) => {
|
||||
if (!pipeline.nightVision) return;
|
||||
if (typeof nightVisionOn === 'boolean') {
|
||||
const action = nightVisionOn ? 'off' : 'on';
|
||||
const action = nightVisionOn ? 'on' : 'off';
|
||||
pipeline.sendNightVision(action);
|
||||
} else {
|
||||
pipeline.sendNightVision('toggle');
|
||||
|
||||
Reference in New Issue
Block a user