enhance: polish voice
This commit is contained in:
@@ -309,3 +309,8 @@ svg:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
/* camera video object-fit */
|
||||
|
||||
[id^="CAMERA_"] video {
|
||||
object-fit: cover !important;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { memo, useEffect } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { useGetAgoraChannelsQuery, useGetAgoraStatusQuery, useGenerateAgoraTokenMutation } from '../../app/services/server';
|
||||
import { updateChannelVisibleAside } from '../../app/slices/footprint';
|
||||
import { addVoiceMember, removeVoiceMember, updateConnectionState, updateDeafenStatus, updateMuteStatus, updateVoicingInfo, updateVoicingMember, updateVoicingNetworkQuality, upsertVoiceList } from '../../app/slices/voice';
|
||||
import { addVoiceMember, removeVoiceMember, updateConnectionState, updateDeafenStatus, updateMuteStatus, updatePin, updateVoicingInfo, updateVoicingMember, updateVoicingNetworkQuality, upsertVoiceList } from '../../app/slices/voice';
|
||||
import { useAppSelector } from '../../app/store';
|
||||
import AudioJoin from '../../assets/join.wav';
|
||||
import { playAgoraVideo } from '../utils';
|
||||
@@ -202,6 +202,8 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
|
||||
};
|
||||
const openCamera = async () => {
|
||||
const localVideoTrack = await AgoraRTC.createCameraVideoTrack();
|
||||
// 取消正在进行的桌面共享
|
||||
await stopShareScreen();
|
||||
await window.VOICE_CLIENT?.publish(localVideoTrack);
|
||||
dispatch(updateVoicingInfo({
|
||||
video: true,
|
||||
@@ -253,7 +255,7 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
|
||||
const startShareScreen = async () => {
|
||||
try {
|
||||
const localVideoTrack = await AgoraRTC.createScreenVideoTrack({
|
||||
electronScreenSourceId: "share_screen",
|
||||
// electronScreenSourceId: "share_screen",
|
||||
selfBrowserSurface: "exclude",
|
||||
// 配置屏幕共享编码参数,详情请查看 API 文档。
|
||||
encoderConfig: "1080p_1",
|
||||
@@ -273,6 +275,11 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
|
||||
// 放到全局变量里
|
||||
window.VIDEO_TRACK_MAP[loginUid] = localVideoTrack;
|
||||
playAgoraVideo(loginUid);
|
||||
// 进入全屏并Pin自己
|
||||
if (context == "channel") {
|
||||
dispatch(updateChannelVisibleAside({ id, aside: "voice_fullscreen" }));
|
||||
dispatch(updatePin({ uid: loginUid, action: "pin" }));
|
||||
}
|
||||
// 监听屏幕共享结束事件
|
||||
if ("close" in localVideoTrack) {
|
||||
localVideoTrack.getMediaStreamTrack().onended = () => {
|
||||
@@ -281,7 +288,6 @@ const useVoice = ({ id, context = "channel" }: VoiceProps) => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("start share screen error", error);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ const Layout: FC<Props> = ({
|
||||
{aside}
|
||||
</div>}
|
||||
{users && <div className="hidden md:block">{users}</div>}
|
||||
{voice && <div className="absolute right-11 top-14 h-fit overflow-y-scroll bg-white dark:!bg-gray-700 md:block">{voice}</div>}
|
||||
{voice && <div className="max-md:absolute max-md:right-11 max-md:top-14 max-md:h-fit max-md:overflow-y-scroll bg-white dark:!bg-gray-700 md:block">{voice}</div>}
|
||||
{!readonly && inputMode == "text" && isActive && (
|
||||
<DnDTip context={context} name={name} />
|
||||
)}
|
||||
|
||||
@@ -106,8 +106,13 @@ const VoiceManagement = ({ id, context, info, setMute, leave, closeCamera, openC
|
||||
{muted ? <IconMicOff className="w-4 fill-gray-500 dark:fill-gray-400" /> : <IconMic className="w-4 fill-gray-500 dark:fill-gray-400" />}
|
||||
</div>
|
||||
</div>
|
||||
<div onDoubleClick={handleFullscreen.bind(null, uid)} id={`CAMERA_${uid}`} className="w-[98%] rounded overflow-hidden m-auto">
|
||||
{/* camera placeholder */}
|
||||
<div className="overflow-hidden group rounded relative" onDoubleClick={handleFullscreen.bind(null, uid)}>
|
||||
<div id={`CAMERA_${uid}`} className="w-[98%] m-auto">
|
||||
{/* camera placeholder */}
|
||||
</div>
|
||||
<button onClick={handleFullscreen.bind(null, uid)} className="invisible group-hover:visible w-5 h-5 p-1 bg-black/40 top-1 right-1.5 absolute rounded">
|
||||
<IconFullscreen className="w-full h-full fill-white" />
|
||||
</button>
|
||||
</div>
|
||||
</li>;
|
||||
})}
|
||||
@@ -127,7 +132,7 @@ const VoiceManagement = ({ id, context, info, setMute, leave, closeCamera, openC
|
||||
</Tooltip>
|
||||
<Tooltip tip={"Share Screen"} placement="top">
|
||||
<li role={"button"} onClick={shareScreen ? stopShareScreen : startShareScreen} className={clsx("py-2 px-3 rounded ", shareScreen ? "bg-green-700" : "bg-gray-100 dark:bg-gray-900")}>
|
||||
<IconScreen className="fill-gray-700 dark:fill-gray-300" />
|
||||
<IconScreen className={clsx("dark:fill-gray-300", shareScreen ? "fill-gray-200" : "fill-gray-800")} />
|
||||
</li>
|
||||
</Tooltip>
|
||||
<Tooltip tip={"Fullscreen"} placement="top">
|
||||
|
||||
@@ -84,7 +84,7 @@ const VoiceFullscreen = ({ id, context }: Props) => {
|
||||
<div className="px-7 py-6 flex justify-between">
|
||||
<span className='text-sm font-semibold'>{_name}</span>
|
||||
<div className="flex gap-4">
|
||||
<IconExitScreen role="button" onClick={handleExitFullscreen} className="fill-gray-300" />
|
||||
<IconExitScreen role="button" onClick={handleExitFullscreen} className="fill-gray-200" />
|
||||
</div>
|
||||
</div>
|
||||
{/* middle */}
|
||||
@@ -111,15 +111,15 @@ const VoiceFullscreen = ({ id, context }: Props) => {
|
||||
{shareScreen ? <div className={clsx("w-1 h-1 absolute z-40 rounded-full bg-green-700/60", special ? "top-2 left-2" : "top-1 left-1 px-2")} /> : null}
|
||||
{!disablePin &&
|
||||
<Tooltip tip={"Remove pin"} disabled={!special} placement="right">
|
||||
<button data-uid={uid} data-action={special ? "unpin" : "pin"} role={"button"} onClick={handlePin} className={clsx("absolute left-1 top-1 z-40 p-1 rounded bg-black/50", special ? "" : "invisible group-hover:visible")}>
|
||||
{special ? <IconPin className="w-3 h-3 fill-gray-300" /> : <IconPin className="w-3 h-3 fill-gray-300" />}
|
||||
<button data-uid={uid} data-action={special ? "unpin" : "pin"} role={"button"} onClick={handlePin} className={clsx("absolute left-1 top-1 z-40 p-1 rounded bg-black/50", special ? "px-2 py-0.5" : "invisible group-hover:visible")}>
|
||||
{special ? <IconPin className={clsx("fill-gray-200", special ? "w-4" : "w-3")} /> : <IconPin className={clsx("fill-gray-200", special ? "w-4" : "w-3")} />}
|
||||
</button>
|
||||
</Tooltip>}
|
||||
<span className={clsx("text-gray-300 bg-black/50 rounded-lg absolute z-40", special ? "left-2 bottom-2 px-2 py-1 text-sm " : "left-1 bottom-1 p-1 text-xs")} title={curr?.name}>
|
||||
{curr?.name}
|
||||
</span>
|
||||
<div className={clsx("flex items-center gap-2 absolute z-40 rounded bg-black/50", special ? "bottom-2 right-2 px-2 py-0.5" : "bottom-1 right-1 px-2")}>
|
||||
{muted ? <IconMicOff className={clsx("fill-gray-300", special ? "w-4" : "w-3")} /> : <IconMic className={clsx(" fill-gray-300 ", special ? "w-4" : "w-3")} />}
|
||||
{muted ? <IconMicOff className={clsx("fill-gray-200", special ? "w-4" : "w-3")} /> : <IconMic className={clsx("fill-gray-200 ", special ? "w-4" : "w-3")} />}
|
||||
</div>
|
||||
<div id={`CAMERA_${uid}`} className={clsx("absolute top-0 left-0 z-30 w-full h-full overflow-hidden m-auto", special ? "" : "rounded")}>
|
||||
{/* camera placeholder */}
|
||||
@@ -132,17 +132,17 @@ const VoiceFullscreen = ({ id, context }: Props) => {
|
||||
<ul className='py-4 flex justify-center gap-2'>
|
||||
<Tooltip tip={muted ? t("unmute") : t("mute")} placement="top">
|
||||
<li role={"button"} onClick={setMute.bind(null, !muted)} className="flex-center py-1 px-3 rounded bg-gray-100 dark:bg-gray-900">
|
||||
{muted ? <IconMicOff className="fill-gray-700 dark:fill-gray-300" /> : <IconMic className="fill-gray-700 dark:fill-gray-300" />}
|
||||
{muted ? <IconMicOff className="fill-gray-700 dark:fill-gray-200" /> : <IconMic className="fill-gray-700 dark:fill-gray-200" />}
|
||||
</li>
|
||||
</Tooltip>
|
||||
<Tooltip tip={video ? t("camera_off") : t("camera_on")} placement="top">
|
||||
<li role={"button"} onClick={video ? closeCamera : openCamera} className="flex-center py-1 px-3 rounded bg-gray-100 dark:bg-gray-900">
|
||||
{video ? <IconCamera className="fill-gray-700 dark:fill-gray-300" /> : <IconCameraOff className="fill-gray-700 dark:fill-gray-300" />}
|
||||
{video ? <IconCamera className="fill-gray-700 dark:fill-gray-200" /> : <IconCameraOff className="fill-gray-700 dark:fill-gray-200" />}
|
||||
</li>
|
||||
</Tooltip>
|
||||
<Tooltip tip={"Share Screen"} placement="top">
|
||||
<li role={"button"} onClick={shareScreen ? stopShareScreen : startShareScreen} className={clsx("flex-center py-1 px-3 rounded ", shareScreen ? "bg-green-700" : "bg-gray-100 dark:bg-gray-900")}>
|
||||
<IconScreen className={clsx("dark:fill-gray-300 w-6 h-6", shareScreen ? "fill-gray-300" : "fill-gray-700")} />
|
||||
<IconScreen className={clsx("dark:fill-gray-200 w-6 h-6", shareScreen ? "fill-gray-200" : "fill-gray-700")} />
|
||||
</li>
|
||||
</Tooltip>
|
||||
<StyledButton onClick={leave} className='bg-red-600 hover:!bg-red-700 text-center'>
|
||||
|
||||
Reference in New Issue
Block a user