mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-05 14:47:40 +03:00
Address review feedback: drag edge cases and test clarity
- Add onMouseLeave handler to cancel drag when cursor leaves overlay - Preserve autotracking zooming disable-on-failure during init - Extract 20px drag threshold as MIN_DRAG_DISTANCE constant - Add sync-with-source notes to replicated test helpers Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4dfc248df4
commit
4a00dbca9d
@ -295,6 +295,13 @@ class OnvifController:
|
|||||||
):
|
):
|
||||||
del move_request["Speed"]["Zoom"]
|
del move_request["Speed"]["Zoom"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
if (
|
||||||
|
self.config.cameras[camera_name].onvif.autotracking.zooming
|
||||||
|
== ZoomingModeEnum.relative
|
||||||
|
):
|
||||||
|
self.config.cameras[
|
||||||
|
camera_name
|
||||||
|
].onvif.autotracking.zooming = ZoomingModeEnum.disabled
|
||||||
logger.warning(
|
logger.warning(
|
||||||
f"Relative zoom not supported for {camera_name}: {e}"
|
f"Relative zoom not supported for {camera_name}: {e}"
|
||||||
)
|
)
|
||||||
|
|||||||
@ -20,7 +20,12 @@ class OnvifCommandEnum(str, Enum):
|
|||||||
|
|
||||||
|
|
||||||
class TestMoveRelativeParsing(TestCase):
|
class TestMoveRelativeParsing(TestCase):
|
||||||
"""Test the move_relative command parameter parsing logic."""
|
"""Test the move_relative command parameter parsing logic.
|
||||||
|
|
||||||
|
NOTE: _parse_move_relative replicates logic from
|
||||||
|
OnvifController.handle_command_async (frigate/ptz/onvif.py).
|
||||||
|
If that parsing changes, this helper must be updated to match.
|
||||||
|
"""
|
||||||
|
|
||||||
def _parse_move_relative(self, param: str):
|
def _parse_move_relative(self, param: str):
|
||||||
"""Replicate the parsing logic from OnvifController.handle_command_async."""
|
"""Replicate the parsing logic from OnvifController.handle_command_async."""
|
||||||
@ -57,8 +62,10 @@ class TestMoveRelativeParsing(TestCase):
|
|||||||
class TestDispatcherPtzParsing(TestCase):
|
class TestDispatcherPtzParsing(TestCase):
|
||||||
"""Test the dispatcher's _on_ptz_command parsing pipeline.
|
"""Test the dispatcher's _on_ptz_command parsing pipeline.
|
||||||
|
|
||||||
Replicates the logic from FrigateDispatcher._on_ptz_command to verify
|
Replicates the logic from FrigateDispatcher._on_ptz_command
|
||||||
that MQTT payloads are correctly decomposed into command + param.
|
(frigate/comms/dispatcher.py) to verify that MQTT payloads are
|
||||||
|
correctly decomposed into command + param.
|
||||||
|
If that parsing changes, this helper must be updated to match.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _parse_ptz_payload(self, payload: str):
|
def _parse_ptz_payload(self, payload: str):
|
||||||
|
|||||||
@ -131,6 +131,9 @@ type LiveCameraViewProps = {
|
|||||||
toggleFullscreen: () => void;
|
toggleFullscreen: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Minimum drag distance (px) to distinguish a drag-to-zoom from a click-to-move. */
|
||||||
|
const MIN_DRAG_DISTANCE = 20;
|
||||||
|
|
||||||
function getClientPos(
|
function getClientPos(
|
||||||
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
|
e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>,
|
||||||
): { x: number; y: number } | null {
|
): { x: number; y: number } | null {
|
||||||
@ -293,8 +296,7 @@ export default function LiveCameraView({
|
|||||||
const dx = Math.abs(pos.x - dragStart.x);
|
const dx = Math.abs(pos.x - dragStart.x);
|
||||||
const dy = Math.abs(pos.y - dragStart.y);
|
const dy = Math.abs(pos.y - dragStart.y);
|
||||||
|
|
||||||
// Minimum drag distance of 20px to distinguish from click
|
if (dx < MIN_DRAG_DISTANCE && dy < MIN_DRAG_DISTANCE) {
|
||||||
if (dx < 20 && dy < 20) {
|
|
||||||
// Click (not drag) — move to point without zoom
|
// Click (not drag) — move to point without zoom
|
||||||
const normalizedX = (pos.x - rect.left) / rect.width;
|
const normalizedX = (pos.x - rect.left) / rect.width;
|
||||||
const normalizedY = (pos.y - rect.top) / rect.height;
|
const normalizedY = (pos.y - rect.top) / rect.height;
|
||||||
@ -352,7 +354,7 @@ export default function LiveCameraView({
|
|||||||
if (!isDragging || !clickOverlayRef.current) return null;
|
if (!isDragging || !clickOverlayRef.current) return null;
|
||||||
const dx = Math.abs(dragCurrent.x - dragStart.x);
|
const dx = Math.abs(dragCurrent.x - dragStart.x);
|
||||||
const dy = Math.abs(dragCurrent.y - dragStart.y);
|
const dy = Math.abs(dragCurrent.y - dragStart.y);
|
||||||
if (dx < 20 && dy < 20) return null; // Don't show rectangle for small movements
|
if (dx < MIN_DRAG_DISTANCE && dy < MIN_DRAG_DISTANCE) return null;
|
||||||
|
|
||||||
const rect = clickOverlayRef.current.getBoundingClientRect();
|
const rect = clickOverlayRef.current.getBoundingClientRect();
|
||||||
const x1 = Math.min(dragStart.x, dragCurrent.x) - rect.left;
|
const x1 = Math.min(dragStart.x, dragCurrent.x) - rect.left;
|
||||||
@ -762,6 +764,10 @@ export default function LiveCameraView({
|
|||||||
onMouseDown={handleOverlayMouseDown}
|
onMouseDown={handleOverlayMouseDown}
|
||||||
onMouseMove={handleOverlayMouseMove}
|
onMouseMove={handleOverlayMouseMove}
|
||||||
onMouseUp={handleOverlayMouseUp}
|
onMouseUp={handleOverlayMouseUp}
|
||||||
|
onMouseLeave={() => {
|
||||||
|
setDragStart(null);
|
||||||
|
setDragCurrent(null);
|
||||||
|
}}
|
||||||
onTouchStart={handleOverlayMouseDown}
|
onTouchStart={handleOverlayMouseDown}
|
||||||
onTouchMove={handleOverlayMouseMove}
|
onTouchMove={handleOverlayMouseMove}
|
||||||
onTouchEnd={handleOverlayMouseUp}
|
onTouchEnd={handleOverlayMouseUp}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user