allowing showing video in footer controls
This commit is contained in:
@@ -63,6 +63,12 @@ function useSocketFire() {
|
|||||||
return { handleConnectToLine, handleTuneIntoLine, handleUntuneFromLine };
|
return { handleConnectToLine, handleTuneIntoLine, handleUntuneFromLine };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const videoConstraints = {
|
||||||
|
frameRate: 15,
|
||||||
|
width: { max: 720, ideal: 720, min: 100 },
|
||||||
|
height: { max: 720, ideal: 720, min: 100 },
|
||||||
|
};
|
||||||
|
|
||||||
interface IConversationContext {
|
interface IConversationContext {
|
||||||
conversationMap: ConversationMap;
|
conversationMap: ConversationMap;
|
||||||
|
|
||||||
@@ -78,6 +84,10 @@ interface IConversationContext {
|
|||||||
handleEscape?: () => void;
|
handleEscape?: () => void;
|
||||||
|
|
||||||
updateConversationPriority?: (conversationId: string, newState: MemberState) => Promise<void>;
|
updateConversationPriority?: (conversationId: string, newState: MemberState) => Promise<void>;
|
||||||
|
|
||||||
|
userLocalStream?: MediaStream;
|
||||||
|
handleCastVideo?: () => void;
|
||||||
|
handleStopVideo?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConversationContext = React.createContext<IConversationContext>({
|
const ConversationContext = React.createContext<IConversationContext>({
|
||||||
@@ -412,6 +422,7 @@ export function ConversationProvider({ children }: { children: React.ReactNode }
|
|||||||
return [priorityConversations, inboxConversations];
|
return [priorityConversations, inboxConversations];
|
||||||
}, [conversationMap, user]);
|
}, [conversationMap, user]);
|
||||||
|
|
||||||
|
// move from priority to inbox and vice versa
|
||||||
const updateConversationPriorityHandler = useCallback(
|
const updateConversationPriorityHandler = useCallback(
|
||||||
async (conversationId: string, newState: MemberState) => {
|
async (conversationId: string, newState: MemberState) => {
|
||||||
try {
|
try {
|
||||||
@@ -435,6 +446,22 @@ export function ConversationProvider({ children }: { children: React.ReactNode }
|
|||||||
[setConversationMap, user],
|
[setConversationMap, user],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const [userLocalStream, setUserLocalStream] = useState<MediaStream>();
|
||||||
|
const handleCastVideo = useCallback(() => {
|
||||||
|
// create a new stream
|
||||||
|
// if there's a selected conversation, then send it to that conversation
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getUserMedia({ video: videoConstraints, audio: false })
|
||||||
|
.then((userStream: MediaStream) => {
|
||||||
|
setUserLocalStream(userStream);
|
||||||
|
})
|
||||||
|
.catch((error) => toast.error('problem getting video'));
|
||||||
|
}, [setUserLocalStream]);
|
||||||
|
|
||||||
|
const handleStopVideo = useCallback(() => {
|
||||||
|
setUserLocalStream(undefined);
|
||||||
|
}, [setUserLocalStream]);
|
||||||
|
|
||||||
const handleEscape = useCallback(() => {
|
const handleEscape = useCallback(() => {
|
||||||
selectConversation(undefined);
|
selectConversation(undefined);
|
||||||
}, [selectConversation]);
|
}, [selectConversation]);
|
||||||
@@ -473,6 +500,9 @@ export function ConversationProvider({ children }: { children: React.ReactNode }
|
|||||||
inboxConversations: masterConversations[1],
|
inboxConversations: masterConversations[1],
|
||||||
handleEscape,
|
handleEscape,
|
||||||
updateConversationPriority: updateConversationPriorityHandler,
|
updateConversationPriority: updateConversationPriorityHandler,
|
||||||
|
userLocalStream,
|
||||||
|
handleStopVideo,
|
||||||
|
handleCastVideo,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@@ -493,12 +523,6 @@ export default function useConversations() {
|
|||||||
return React.useContext(ConversationContext);
|
return React.useContext(ConversationContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
const videoConstraints = {
|
|
||||||
frameRate: 15,
|
|
||||||
width: { max: 100 },
|
|
||||||
height: { max: 200 },
|
|
||||||
};
|
|
||||||
|
|
||||||
const iceServers = [
|
const iceServers = [
|
||||||
// { urls: 'stun:stun.l.google.com:19302' },
|
// { urls: 'stun:stun.l.google.com:19302' },
|
||||||
// { urls: 'stun:stun.l.google.com:19302' },
|
// { urls: 'stun:stun.l.google.com:19302' },
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import {
|
|||||||
FiZap,
|
FiZap,
|
||||||
FiZapOff,
|
FiZapOff,
|
||||||
} from 'react-icons/fi';
|
} from 'react-icons/fi';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { MasterConversation } from '../util/types';
|
import { MasterConversation } from '../util/types';
|
||||||
import { MdOutlineRecordVoiceOver } from 'react-icons/md';
|
import { MdOutlineRecordVoiceOver } from 'react-icons/md';
|
||||||
@@ -46,7 +46,13 @@ import useZen from '../providers/ZenProvider';
|
|||||||
export default function FooterControls() {
|
export default function FooterControls() {
|
||||||
const { handleFlowState } = useZen();
|
const { handleFlowState } = useZen();
|
||||||
|
|
||||||
const { selectedConversation, priorityConversations } = useConversations();
|
const {
|
||||||
|
selectedConversation,
|
||||||
|
priorityConversations,
|
||||||
|
userLocalStream,
|
||||||
|
handleCastVideo,
|
||||||
|
handleStopVideo,
|
||||||
|
} = useConversations();
|
||||||
const { user, handleLogout } = useAuth();
|
const { user, handleLogout } = useAuth();
|
||||||
|
|
||||||
const { handleToggleDesktopMode, desktopMode } = useElectron();
|
const { handleToggleDesktopMode, desktopMode } = useElectron();
|
||||||
@@ -77,8 +83,16 @@ export default function FooterControls() {
|
|||||||
const [isVideoOn, setIsVideoOn] = useState<boolean>(false);
|
const [isVideoOn, setIsVideoOn] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleToggleVideo = useCallback(() => {
|
const handleToggleVideo = useCallback(() => {
|
||||||
setIsVideoOn((prevVal) => !prevVal);
|
setIsVideoOn((prevVal) => {
|
||||||
}, [setIsVideoOn]);
|
if (!prevVal) {
|
||||||
|
handleCastVideo();
|
||||||
|
} else {
|
||||||
|
handleStopVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
return !prevVal;
|
||||||
|
});
|
||||||
|
}, [setIsVideoOn, handleCastVideo, handleStopVideo]);
|
||||||
|
|
||||||
const handleCloseUserSettings = useCallback(() => {
|
const handleCloseUserSettings = useCallback(() => {
|
||||||
setOpenUserSettings(false);
|
setOpenUserSettings(false);
|
||||||
@@ -96,6 +110,13 @@ export default function FooterControls() {
|
|||||||
return false;
|
return false;
|
||||||
}, [selectedConversation, priorityConversations]);
|
}, [selectedConversation, priorityConversations]);
|
||||||
|
|
||||||
|
const localVideoRef = useRef<HTMLVideoElement>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (localVideoRef?.current && userLocalStream) {
|
||||||
|
localVideoRef.current.srcObject = userLocalStream;
|
||||||
|
}
|
||||||
|
}, [localVideoRef, userLocalStream]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@@ -162,7 +183,11 @@ export default function FooterControls() {
|
|||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded={open ? 'true' : undefined}
|
aria-expanded={open ? 'true' : undefined}
|
||||||
>
|
>
|
||||||
<Avatar alt={user.givenName} src={user.picture} />
|
{isVideoOn ? (
|
||||||
|
<Box height={60} width={40} ref={localVideoRef} component={'video'} autoPlay />
|
||||||
|
) : (
|
||||||
|
<Avatar alt={user.givenName} src={user.picture} />
|
||||||
|
)}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
<Divider orientation="horizontal" flexItem />
|
<Divider orientation="horizontal" flexItem />
|
||||||
@@ -188,7 +213,8 @@ function OverlayConversation({
|
|||||||
}) {
|
}) {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
|
|
||||||
const { selectConversation, handleEscape, updateConversationPriority } = useConversations();
|
const { selectConversation, handleEscape, updateConversationPriority, userLocalStream } =
|
||||||
|
useConversations();
|
||||||
|
|
||||||
const handleSelectConversation = useCallback(() => {
|
const handleSelectConversation = useCallback(() => {
|
||||||
if (!isSelected) {
|
if (!isSelected) {
|
||||||
@@ -215,6 +241,10 @@ function OverlayConversation({
|
|||||||
updateConversationPriority(masterConversation._id.toString(), 'priority');
|
updateConversationPriority(masterConversation._id.toString(), 'priority');
|
||||||
}, [updateConversationPriority, isPriority, masterConversation._id]);
|
}, [updateConversationPriority, isPriority, masterConversation._id]);
|
||||||
|
|
||||||
|
const userVideoRef = useRef<HTMLVideoElement>(null);
|
||||||
|
|
||||||
|
useEffect(() => {}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
direction={'column'}
|
direction={'column'}
|
||||||
@@ -264,8 +294,8 @@ function OverlayConversation({
|
|||||||
}}
|
}}
|
||||||
max={3}
|
max={3}
|
||||||
>
|
>
|
||||||
{masterConversation.members?.map(
|
{masterConversation.members?.map((conversationUser, index) => {
|
||||||
(conversationUser, index) =>
|
return (
|
||||||
(conversationUser._id.toString() !== user._id.toString() || isSelected) && (
|
(conversationUser._id.toString() !== user._id.toString() || isSelected) && (
|
||||||
<Avatar
|
<Avatar
|
||||||
key={`${masterConversation._id.toString()}-${conversationUser._id.toString()}-convoIcon`}
|
key={`${masterConversation._id.toString()}-${conversationUser._id.toString()}-convoIcon`}
|
||||||
@@ -279,8 +309,9 @@ function OverlayConversation({
|
|||||||
: '20%',
|
: '20%',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
),
|
)
|
||||||
)}
|
);
|
||||||
|
})}
|
||||||
</AvatarGroup>
|
</AvatarGroup>
|
||||||
|
|
||||||
{isSelected && (
|
{isSelected && (
|
||||||
|
|||||||
Reference in New Issue
Block a user