Fixed mediacontrol buttons on mobile

This commit is contained in:
James Ketr 2025-09-16 10:46:48 -07:00
parent 1204a5ef21
commit a0148fe8b9
2 changed files with 67 additions and 4 deletions

View File

@ -1340,6 +1340,18 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
const spacerRef = useRef<HTMLDivElement>(null); const spacerRef = useRef<HTMLDivElement>(null);
const moveableRef = useRef<any>(null); const moveableRef = useRef<any>(null);
const [isDragging, setIsDragging] = useState<boolean>(false); const [isDragging, setIsDragging] = useState<boolean>(false);
// Reset drag state on pointerup/touchend/mouseup anywhere in the document
useEffect(() => {
const resetDrag = () => setIsDragging(false);
document.addEventListener("pointerup", resetDrag);
document.addEventListener("touchend", resetDrag);
document.addEventListener("mouseup", resetDrag);
return () => {
document.removeEventListener("pointerup", resetDrag);
document.removeEventListener("touchend", resetDrag);
document.removeEventListener("mouseup", resetDrag);
};
}, []);
useEffect(() => { useEffect(() => {
console.log( console.log(
@ -1600,15 +1612,15 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
> >
<Box className="Controls"> <Box className="Controls">
{isSelf ? ( {isSelf ? (
<IconButton onClick={toggleMute} onTouchStart={toggleMute}> <IconButton onClick={toggleMute}>
{muted ? <MicOff color={colorAudio} /> : <Mic color={colorAudio} />} {muted ? <MicOff color={colorAudio} /> : <Mic color={colorAudio} />}
</IconButton> </IconButton>
) : ( ) : (
<IconButton onClick={toggleMute} onTouchStart={toggleMute}> <IconButton onClick={toggleMute}>
{muted ? <VolumeOff color={colorAudio} /> : <VolumeUp color={colorAudio} />} {muted ? <VolumeOff color={colorAudio} /> : <VolumeUp color={colorAudio} />}
</IconButton> </IconButton>
)} )}
<IconButton onClick={toggleVideo} onTouchStart={toggleVideo}> <IconButton onClick={toggleVideo}>
{videoOn ? <Videocam color={colorVideo} /> : <VideocamOff color={colorVideo} />} {videoOn ? <Videocam color={colorVideo} /> : <VideocamOff color={colorVideo} />}
</IconButton> </IconButton>
</Box> </Box>
@ -1651,6 +1663,15 @@ const MediaControl: React.FC<MediaControlProps> = ({ isSelf, peer, className })
origin={false} origin={false}
edge edge
onDragStart={(e) => { onDragStart={(e) => {
// Only block drag if the event is a pointerdown/touchstart on a button, but do not interfere with click/touch events
const controls = containerRef.current?.querySelector('.Controls');
const target = e.inputEvent?.target as HTMLElement;
if (controls && target && (target.closest('button') || target.closest('.MuiIconButton-root'))) {
if (typeof e.stopDrag === 'function') {
e.stopDrag();
}
return;
}
setIsDragging(true); setIsDragging(true);
}} }}
onDrag={(e) => { onDrag={(e) => {

View File

@ -116,7 +116,7 @@ const UserList: React.FC<UserListProps> = (props: UserListProps) => {
const message = JSON.parse(event.data); const message = JSON.parse(event.data);
const data: any = message.data; const data: any = message.data;
switch (message.type) { switch (message.type) {
case "lobby_state": case "lobby_state": {
type LobbyStateData = { type LobbyStateData = {
participants: User[]; participants: User[];
}; };
@ -128,6 +128,14 @@ const UserList: React.FC<UserListProps> = (props: UserListProps) => {
lobby_state.participants.sort(sortUsers); lobby_state.participants.sort(sortUsers);
setUsers(lobby_state.participants); setUsers(lobby_state.participants);
break; break;
}
case "update_name": {
// Update local session name immediately
if (data && typeof data.name === "string") {
session.name = data.name;
}
break;
}
default: default:
break; break;
} }
@ -143,6 +151,19 @@ const UserList: React.FC<UserListProps> = (props: UserListProps) => {
}); });
}, [users, sendJsonMessage]); }, [users, sendJsonMessage]);
// Add state for name change UI
const [newName, setNewName] = useState("");
const [changingName, setChangingName] = useState(false);
// Handler for changing name
const handleChangeName = () => {
if (!newName.trim()) return;
setChangingName(true);
sendJsonMessage({ type: "set_name", data: { name: newName } });
setNewName("");
setTimeout(() => setChangingName(false), 1000); // UI feedback
};
return ( return (
<Box sx={{ position: "relative", width: "100%" }}> <Box sx={{ position: "relative", width: "100%" }}>
<Paper <Paper
@ -153,6 +174,27 @@ const UserList: React.FC<UserListProps> = (props: UserListProps) => {
m: { xs: 0, sm: 2 }, m: { xs: 0, sm: 2 },
}} }}
> >
{/* Name change UI for local user */}
{session && (
<Box sx={{ mb: 2, display: "flex", alignItems: "center", gap: 1 }}>
<input
type="text"
value={newName}
onChange={(e) => setNewName(e.target.value)}
placeholder="Change your name"
style={{ fontSize: "1em", padding: "4px 8px", borderRadius: 4, border: "1px solid #ccc" }}
disabled={changingName}
/>
<Button
variant="contained"
size="small"
onClick={handleChangeName}
disabled={changingName || !newName.trim()}
>
{changingName ? "Changing..." : "Change Name"}
</Button>
</Box>
)}
<MediaAgent {...{ session, socketUrl, peers, setPeers }} /> <MediaAgent {...{ session, socketUrl, peers, setPeers }} />
<List className="UserSelector"> <List className="UserSelector">
{users?.map((user) => ( {users?.map((user) => (