Double tap to toggle moved MediaControl
This commit is contained in:
parent
0d1024ff61
commit
d12d87a796
@ -1322,6 +1322,14 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
width?: number;
|
width?: number;
|
||||||
height?: number;
|
height?: number;
|
||||||
}>({ translate: [0, 0] });
|
}>({ translate: [0, 0] });
|
||||||
|
// Remember last released moveable position/size so we can restore to it
|
||||||
|
const lastSavedRef = useRef<{
|
||||||
|
translate: [number, number];
|
||||||
|
width?: number;
|
||||||
|
height?: number;
|
||||||
|
} | null>(null);
|
||||||
|
// Whether the target is currently snapped to the spacer (true) or in a free position (false)
|
||||||
|
const [isAttached, setIsAttached] = useState<boolean>(true);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const targetRef = useRef<HTMLDivElement>(null);
|
const targetRef = useRef<HTMLDivElement>(null);
|
||||||
const spacerRef = useRef<HTMLDivElement>(null);
|
const spacerRef = useRef<HTMLDivElement>(null);
|
||||||
@ -1341,6 +1349,40 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Double-click toggles between spacer-attached and last saved free position
|
||||||
|
const handleDoubleClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
// Ignore double-clicks on control buttons
|
||||||
|
const targetEl = e.target as HTMLElement | null;
|
||||||
|
if (targetEl && (targetEl.closest("button") || targetEl.closest(".MuiIconButton-root"))) return;
|
||||||
|
|
||||||
|
if (!targetRef.current || !spacerRef.current) return;
|
||||||
|
|
||||||
|
// If currently attached to spacer -> restore to last saved moveable position
|
||||||
|
if (isAttached) {
|
||||||
|
const last = lastSavedRef.current;
|
||||||
|
if (last) {
|
||||||
|
targetRef.current.style.transform = `translate(${last.translate[0]}px, ${last.translate[1]}px)`;
|
||||||
|
if (typeof last.width === "number") targetRef.current.style.width = `${last.width}px`;
|
||||||
|
if (typeof last.height === "number") targetRef.current.style.height = `${last.height}px`;
|
||||||
|
setFrame(last);
|
||||||
|
setIsAttached(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not attached -> move back to spacer (origin)
|
||||||
|
const spacerRect = spacerRef.current.getBoundingClientRect();
|
||||||
|
targetRef.current.style.transform = "translate(0px, 0px)";
|
||||||
|
targetRef.current.style.width = `${spacerRect.width}px`;
|
||||||
|
targetRef.current.style.height = `${spacerRect.height}px`;
|
||||||
|
setFrame({ translate: [0, 0], width: spacerRect.width, height: spacerRect.height });
|
||||||
|
setIsAttached(true);
|
||||||
|
},
|
||||||
|
[isAttached]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log(
|
console.log(
|
||||||
`media-agent - MediaControl mounted for peer ${peer?.peer_name}, local=${peer?.local}, hasSrcObject=${!!peer
|
`media-agent - MediaControl mounted for peer ${peer?.peer_name}, local=${peer?.local}, hasSrcObject=${!!peer
|
||||||
@ -1579,10 +1621,11 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
opacity: isDragging ? 1 : 0.3,
|
opacity: isDragging ? 1 : 0.3,
|
||||||
transition: "opacity 0.2s",
|
transition: "opacity 0.2s",
|
||||||
}}
|
}}
|
||||||
|
onDoubleClick={handleDoubleClick}
|
||||||
>
|
>
|
||||||
{isDragging && (
|
{isDragging && (
|
||||||
<div
|
<Box
|
||||||
style={{
|
sx={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: "50%",
|
top: "50%",
|
||||||
left: "50%",
|
left: "50%",
|
||||||
@ -1590,10 +1633,11 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
fontSize: "0.7em",
|
fontSize: "0.7em",
|
||||||
color: "#888",
|
color: "#888",
|
||||||
pointerEvents: "none",
|
pointerEvents: "none",
|
||||||
|
userSelect: "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Drop here
|
Drop here
|
||||||
</div>
|
</Box>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1602,6 +1646,7 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
ref={targetRef}
|
ref={targetRef}
|
||||||
className={`MediaControl ${className}`}
|
className={`MediaControl ${className}`}
|
||||||
data-peer={peer.session_id}
|
data-peer={peer.session_id}
|
||||||
|
onDoubleClick={handleDoubleClick}
|
||||||
style={{
|
style={{
|
||||||
position: "absolute",
|
position: "absolute",
|
||||||
top: "0px",
|
top: "0px",
|
||||||
@ -1651,6 +1696,7 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
srcObject={peer.attributes.srcObject}
|
srcObject={peer.attributes.srcObject}
|
||||||
local={peer.local}
|
local={peer.local}
|
||||||
muted={peer.local || muted}
|
muted={peer.local || muted}
|
||||||
|
onDoubleClick={handleDoubleClick}
|
||||||
/>
|
/>
|
||||||
<WebRTCStatus isNegotiating={peer.isNegotiating || false} connectionState={peer.connectionState} />
|
<WebRTCStatus isNegotiating={peer.isNegotiating || false} connectionState={peer.connectionState} />
|
||||||
<WebRTCStatus isNegotiating={peer.isNegotiating || false} connectionState={peer.connectionState} />
|
<WebRTCStatus isNegotiating={peer.isNegotiating || false} connectionState={peer.connectionState} />
|
||||||
@ -1711,19 +1757,29 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
const shouldSnap = checkSnapBack(matrix.m41, matrix.m42);
|
const shouldSnap = checkSnapBack(matrix.m41, matrix.m42);
|
||||||
if (shouldSnap) {
|
if (shouldSnap) {
|
||||||
targetRef.current.style.transform = "translate(0px, 0px)";
|
targetRef.current.style.transform = "translate(0px, 0px)";
|
||||||
setFrame({ translate: [0, 0], width: frame.width, height: frame.height });
|
// Snap back to spacer origin
|
||||||
|
setFrame((prev) => ({ translate: [0, 0], width: prev.width, height: prev.height }));
|
||||||
if (spacerRef.current) {
|
if (spacerRef.current) {
|
||||||
const spacerRect = spacerRef.current.getBoundingClientRect();
|
const spacerRect = spacerRef.current.getBoundingClientRect();
|
||||||
targetRef.current.style.width = `${spacerRect.width}px`;
|
targetRef.current.style.width = `${spacerRect.width}px`;
|
||||||
targetRef.current.style.height = `${spacerRect.height}px`;
|
targetRef.current.style.height = `${spacerRect.height}px`;
|
||||||
setFrame({ translate: [0, 0] });
|
setFrame({ translate: [0, 0], width: spacerRect.width, height: spacerRect.height });
|
||||||
}
|
}
|
||||||
|
// Remember that we're attached to spacer
|
||||||
|
setIsAttached(true);
|
||||||
} else {
|
} else {
|
||||||
setFrame({
|
setFrame({
|
||||||
translate: [matrix.m41, matrix.m42],
|
translate: [matrix.m41, matrix.m42],
|
||||||
width: frame.width,
|
width: frame.width,
|
||||||
height: frame.height,
|
height: frame.height,
|
||||||
});
|
});
|
||||||
|
// Save last free position
|
||||||
|
lastSavedRef.current = {
|
||||||
|
translate: [matrix.m41, matrix.m42],
|
||||||
|
width: frame.width,
|
||||||
|
height: frame.height,
|
||||||
|
};
|
||||||
|
setIsAttached(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setFrame({ translate: [0, 0], width: frame.width, height: frame.height });
|
setFrame({ translate: [0, 0], width: frame.width, height: frame.height });
|
||||||
@ -1748,6 +1804,26 @@ const MediaControl: React.FC<MediaControlProps> = ({
|
|||||||
}}
|
}}
|
||||||
onResizeEnd={() => {
|
onResizeEnd={() => {
|
||||||
setIsDragging(false);
|
setIsDragging(false);
|
||||||
|
// Save last size when user finishes resizing; preserve translate
|
||||||
|
if (targetRef.current) {
|
||||||
|
const computedStyle = getComputedStyle(targetRef.current);
|
||||||
|
const transform = computedStyle.transform;
|
||||||
|
let tx = 0,
|
||||||
|
ty = 0;
|
||||||
|
if (transform && transform !== "none") {
|
||||||
|
const matrix = new DOMMatrix(transform);
|
||||||
|
tx = matrix.m41;
|
||||||
|
ty = matrix.m42;
|
||||||
|
}
|
||||||
|
lastSavedRef.current = {
|
||||||
|
translate: [tx, ty],
|
||||||
|
width: frame.width,
|
||||||
|
height: frame.height,
|
||||||
|
};
|
||||||
|
// If we resized while attached to spacer, consider that we are free
|
||||||
|
if (tx !== 0 || ty !== 0) setIsAttached(false);
|
||||||
|
else setIsAttached(true);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user