Commit a4e226a0 authored by liujiaxin's avatar liujiaxin

feat:添加检测用户是否开启音视频权限功能

parent 788c9a76
......@@ -115,7 +115,13 @@
"pack:win": "npm run electron:build && electron-builder --win"
},
"eslintConfig": {
"extends": "react-app"
"extends": "react-app",
"rules": {
"jsx-a11y/href-no-hash": "off",
"no-throw-literal": "off",
"react-hooks/rules-of-hooks": "off",
"react-hooks/exhaustive-deps": "off"
}
},
"browserslist": {
"production": [
......
import React, { useEffect, useRef, useState } from 'react';
import React from 'react';
import './toast.scss';
import {useGlobalState, useRoomState} from '../containers/root-container';
import { isEmpty } from 'lodash';
import {roomStore} from "../stores/room";
import { useRoomState} from '../containers/root-container';
// import { isEmpty } from 'lodash';
// import {roomStore} from "../stores/room";
import EmojiEventsIcon from "@material-ui/icons/EmojiEvents";
import {eventBus} from "../stores/EventBus";
import Link from "@material-ui/core/Link";
......@@ -35,7 +35,7 @@ export default function AddStarsButton({type, uid}: AddStarsButtonProps) {
const me = useRoomState().me;
const style = useStyles();
const addStar = async () => {
if (me.role != 'teacher') {
if (me.role !== 'teacher') {
return
}
eventBus.emit('showAddStartDialog', {uid})
......
import React, {useRef, useEffect, useMemo, useState} from 'react';
import Icon from './icon';
import React, {useEffect, useState} from 'react';
// import Icon from './icon';
import './video-player.scss';
import { AgoraElectronStream, StreamType, nativeRTCClient as nativeClient } from '../utils/agora-electron-client';
import { useRoomState } from '../containers/root-container';
import { platform } from '../utils/platform';
// import { AgoraElectronStream, StreamType, nativeRTCClient as nativeClient } from '../utils/agora-electron-client';
// import { useRoomState } from '../containers/root-container';
// import { platform } from '../utils/platform';
import {makeStyles} from "@material-ui/core/styles";
import { endPoint } from '../services/agora-end-points';
const contentMode = 0;
// const contentMode = 0;
const useStyles = makeStyles({
......@@ -45,7 +45,8 @@ const useStyles = makeStyles({
const CourseWareFrame: React.FC = () => {
const classes = useStyles();
// `${ENDPOINT}/airclass_ol?token=${this.userToken}`;
let src = endPoint.getCourseUrl();
const cw_src = endPoint.getCourseUrl();
const [src, setSrc] = useState<string>(cw_src);
let refDom: any = null;
const saveRef = (ref: any) => {refDom = ref};
useEffect(() => {
......@@ -60,15 +61,16 @@ const CourseWareFrame: React.FC = () => {
}
return () => {
src = 'about:blank'
setSrc('about:blank');
console.log('iframe to blank');
}
// eslint-disable-next-line
}, []);
return (
<div ref={saveRef} className={classes.style1}>
{/*<svg viewBox="0 0 0 0"></svg>*/}
<iframe id="cwFrame" src={src} className={classes.frm}></iframe>
<iframe title="courseware-player " id="cwFrame" src={src} className={classes.frm}></iframe>
</div>
)
}
......
......@@ -8,7 +8,7 @@ import {roomStore, windowMonitor} from '../../stores/room';
import {globalStore} from '../../stores/global';
import { useHistory } from 'react-router-dom';
import { RoomMessage } from '../../utils/agora-rtm-client';
import {getApiServerHost, goHome} from "../../services/agora-end-points";
import { goHome} from "../../services/agora-end-points";
interface RoomProps {
onConfirm: (type: string) => void
......
import React, {useEffect, useMemo, useRef, useState} from 'react';
import React, {useMemo} from 'react';
import { useRoomState} from '../containers/root-container';
import { isEmpty } from 'lodash';
import {roomStore} from "../stores/room";
// import { isEmpty } from 'lodash';
// import {roomStore} from "../stores/room";
import PanToolIcon from "@material-ui/icons/PanTool";
import './hands-up-icon.scss';
......@@ -22,11 +22,11 @@ export default function HandsUpIcon({id, streamID}: UserStarsProps) {
// }, [state.handsUpStudents]);
const isHandUp = useMemo(() => {
const hu = roomStore.state.handsUpStudents[streamID];
const hu = state.handsUpStudents[streamID];
console.log(streamID, hu)
return hu
}, [roomStore.state.handsUpStudents]);
// eslint-disable-next-line
}, [state]);
return (
......
......@@ -19,11 +19,10 @@ import { roomStore } from '../stores/room';
import { whiteboard } from '../stores/whiteboard';
import { globalStore } from '../stores/global';
import { platform } from '../utils/platform';
import AgoraWebClient, { SHARE_ID } from '../utils/agora-rtc-client';
import AgoraWebClient from '../utils/agora-rtc-client';
import "white-web-sdk/style/index.css";
import { ViewMode } from 'white-web-sdk';
const pathName = (path: string): string => {
const reg = /\/([^/]*)\//g;
reg.exec(path);
......@@ -183,6 +182,7 @@ const MediaBoard: React.FC<MediaBoardProps> = ({
const isHost = useMemo(() => {
return +roomStore.state.me.uid === +roomStore.state.course.linkId;
// eslint-disable-next-line
}, [roomStore.state.me.uid,
roomStore.state.course.linkId]);
......@@ -247,7 +247,7 @@ const MediaBoard: React.FC<MediaBoardProps> = ({
const showControl: boolean = useMemo(() => {
if (me.role === 'teacher') return true;
return false;
}, []);
}, [me.role]);
const items = [
{
......@@ -294,8 +294,10 @@ const items = [
if (['add', 'folder', 'upload'].indexOf(item.name) === -1) {
return item;
}
return null;
})
}, []);
// eslint-disable-next-line
}, [items]);
const drawable: string = useMemo(() => {
if (location.pathname.match('small-class')) {
......@@ -312,6 +314,7 @@ const items = [
}
}
return 'drawable';
// eslint-disable-next-line
}, [me.role, me.grantBoard, location]);
const [tool, setTool] = useState<string | any>(drawable === 'drawable' ? 'pencil' : '');
......@@ -372,6 +375,7 @@ const items = [
}).catch(console.warn);
}
// eslint-disable-next-line
}, []);
useEffect(() => {
......@@ -436,6 +440,7 @@ const items = [
})
}
*/
// eslint-disable-next-line
}, [rtmState.joined, me.boardId, course.boardId]);
const [uploadPhase, updateUploadPhase] = useState<string>('');
......@@ -443,6 +448,7 @@ const items = [
useEffect(() => {
console.log("[mediaboard] uploadPhase: ", uploadPhase, " convertPhase: ", convertPhase);
// eslint-disable-next-line
}, [uploadPhase, convertPhase]);
const UploadPanel = useCallback(() => {
......@@ -483,6 +489,7 @@ const items = [
}
}}
/>)
// eslint-disable-next-line
}, [tool, room]);
useEffect(() => {
......@@ -524,11 +531,12 @@ const items = [
room.setViewMode(ViewMode.Freedom);
}
}
// eslint-disable-next-line
}, [room, roomStore.state.course.lockBoard, roomStore.state.me.role]);
const globalState = useGlobalState();
const scale = whiteboardState.scale ? whiteboardState.scale : 1;
// const scale = whiteboardState.scale ? whiteboardState.scale : 1;
const UploadProgressView = useCallback(() => {
if (uploadPhase === 'uploading') {
......@@ -583,7 +591,7 @@ const items = [
items={toolItems}
currentTool={tool}
handleToolClick={handleToolClick} />
{tool === 'color_picker' && strokeColor && roomStore.state.me.role == 'teacher'?
{tool === 'color_picker' && strokeColor && roomStore.state.me.role === 'teacher'?
<SketchPicker
color={strokeColor}
onChangeComplete={onColorChanged} />
......
import React, { useRef, useEffect, useMemo } from 'react';
import Icon from './icon';
// import Icon from './icon';
import './member-holder.scss';
import { AgoraElectronStream, StreamType, nativeRTCClient as nativeClient } from '../utils/agora-electron-client';
import { nativeRTCClient as nativeClient } from '../utils/agora-electron-client';
import { useRoomState } from '../containers/root-container';
import { platform } from '../utils/platform';
import AccountCircle from '@material-ui/icons/AccountCircle';
import Link from '@material-ui/core/Link';
import PanToolIcon from '@material-ui/icons/PanTool';
import {roomStore} from "../stores/room";
// import PanToolIcon from '@material-ui/icons/PanTool';
// import {roomStore} from "../stores/room";
import UserStars from "./user-stars";
import {eventBus} from "../stores/EventBus";
// import {eventBus} from "../stores/EventBus";
import AddStarsButton, { StarsButtonType } from './add-stars-btn';
import HandsUpIcon from "./hands-up-icon";
const contentMode = 0;
// const contentMode = 0;
interface MemberHolderProps {
id?: string
......@@ -45,10 +45,11 @@ const MemberHolder: React.FC<MemberHolderProps> = ({
const loadVideo = useRef<boolean>(false);
const loadAudio = useRef<boolean>(false);
const lockPlay = useRef<boolean>(false);
// const lockPlay = useRef<boolean>(false);
const AgoraRtcEngine = useMemo(() => {
return nativeClient.rtcEngine;
// eslint-disable-next-line
}, [nativeClient.rtcEngine]);
/*
useEffect(() => {
......@@ -206,12 +207,13 @@ const MemberHolder: React.FC<MemberHolderProps> = ({
}
}
}, [stream, video, AgoraRtcEngine]);
/*
const onAudioClick = (evt: any) => {
if (handleClick && id) {
handleClick('audio', streamID, id);
}
}
*/
const onStageUp = (evt: any) => {
if (handleClick && id) {
......@@ -219,6 +221,7 @@ const MemberHolder: React.FC<MemberHolderProps> = ({
}
}
/*
const onVideoClick = (evt: any) => {
if (handleClick && id) {
handleClick('video', streamID, id);
......@@ -230,12 +233,14 @@ const MemberHolder: React.FC<MemberHolderProps> = ({
handleClose('close', streamID);
}
}
const addStar = (evt: any) => {
if (me.role != 'teacher') {
return
}
eventBus.emit('showAddStartDialog', {uid: id});
}
*/
const me = useRoomState().me;
return (
......
......@@ -13,8 +13,8 @@ import { isElectron, platform } from '../utils/platform';
import { useRoomState } from '../containers/root-container';
import { roomStore } from '../stores/room';
import { globalStore } from '../stores/global';
import VoiceOverOffIcon from '@material-ui/icons/VoiceOverOff';
import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
// import VoiceOverOffIcon from '@material-ui/icons/VoiceOverOff';
// import RecordVoiceOverIcon from '@material-ui/icons/RecordVoiceOver';
import RoomToolsBar from "./room-tools-bar";
interface NavProps {
delay: string
......@@ -123,6 +123,7 @@ export default function NavContainer() {
setTimer(null);
}
}
// eslint-disable-next-line
}, []);
const roomState = useRoomState();
......@@ -169,6 +170,7 @@ export default function NavContainer() {
nativeClient.off('audioquality', () => {});
}
}
// eslint-disable-next-line
}, []);
const courseState = roomState.course.courseState;
......@@ -184,6 +186,7 @@ export default function NavContainer() {
clearInterval(timer);
setTimer(null);
}
// eslint-disable-next-line
}, [courseState]);
const lock = useRef<boolean>(false);
......
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { useGlobalState } from '../containers/root-container';
const useStyles = makeStyles(theme => ({
progress: {
margin: theme.spacing(2),
color: '#44A2FC'
},
container: {
position: 'absolute',
top: '0px',
left: '0px',
height: '100%',
width: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
backgroundColor:'rgba(0, 0, 0, 0.5)',
// opacity: 0.8,
zIndex: 10
},
textWrap:{
padding: 32,
}
}));
export const Permission: React.FC<{}> = () => {
const classes = useStyles();
return (
<div className={classes.container}>
<div>
<div className="custom-card">
<div className="flex-item cover">
<div className="preview-video">
<div className="permission-placeholder"></div>
</div>
</div>
<div className="flex-item card">
<div className={classes.textWrap}>
<h3>提示</h3>
<p>请先开启摄像头、麦克风权限,<b>否则将无法正常上课!!!</b></p>
<p><b>第一步</b>:按照如下方法,设置摄像头/麦克风权限为<b>“允许”</b>
点击浏览器地址旁边的小锁头,在弹出的窗口中,设置摄像头/麦克风权限为<b>“允许”</b></p>
<p><b>第二步</b>:设置完成后,根据提示,点击<b>“重新加载”</b></p>
</div>
</div>
</div>
</div>
</div>
);
}
export default function PermissionContainer () {
const state = useGlobalState();
const permission = state.permission;
return (
permission ? <Permission /> : null
)
}
import React, {useMemo, useState} from 'react';
import ChatPanel from './chat/panel';
import StudentList from './student-list';
import useChatText from '../hooks/use-chat-text';
import { VolumeOff, VolumeUp, ImportExport } from '@material-ui/icons';
import React, {useMemo} from 'react';
// import ChatPanel from './chat/panel';
// import StudentList from './student-list';
// import useChatText from '../hooks/use-chat-text';
// import { VolumeOff, VolumeUp, ImportExport } from '@material-ui/icons';
import {roomStore} from "../stores/room";
import {useRoomState} from "../containers/root-container";
import './room-tools-bar.scss';
......@@ -13,8 +13,8 @@ import ImportContacts from "@material-ui/icons/ImportContacts";
import SettingsApplicationsIcon from '@material-ui/icons/SettingsApplications';
import SettingsPowerIcon from '@material-ui/icons/SettingsPower';
import {TOOL_TYPE} from "../utils/types";
import EmojiEventsIcon from '@material-ui/icons/EmojiEvents';
import {eventBus} from "../stores/EventBus";
// import EmojiEventsIcon from '@material-ui/icons/EmojiEvents';
// import {eventBus} from "../stores/EventBus";
import AddStarsButton, {StarsButtonType} from './add-stars-btn';
type Props = {
......@@ -28,7 +28,7 @@ export default function RoomToolsBar (props: any) {
const roomState = useRoomState();
const changeTool = async () => {
console.log(roomStore.state.course.currentTool);
if (roomStore.state.course.currentTool == TOOL_TYPE.WHITEBOARD) {
if (roomStore.state.course.currentTool === TOOL_TYPE.WHITEBOARD) {
await roomStore.setCurrentTool(TOOL_TYPE.COURSE_WARE)
} else {
await roomStore.setCurrentTool(TOOL_TYPE.WHITEBOARD)
......@@ -38,6 +38,7 @@ export default function RoomToolsBar (props: any) {
return {
currentTool: roomStore.state.course.currentTool
}
// eslint-disable-next-line
}, [roomState]);
const {muteAudio} = useMemo(() => {
......@@ -56,15 +57,15 @@ export default function RoomToolsBar (props: any) {
// const allAddStar = async () => {
// eventBus.emit('showAddStartDialog', {uid: 0})
// }
const randomStageUp = async () => {
await roomStore.randomStageUp()
}
// const randomStageUp = async () => {
// await roomStore.randomStageUp()
// }
return (
<>
<div className={'room-tool-box'}>
{roomStore.state.me.role == 'teacher' ?
{roomStore.state.me.role === 'teacher' ?
<>
<AddStarsButton type={StarsButtonType.BIG} uid={0}></AddStarsButton>
{/*<div className="tool-btn" onClick={allAddStar}><EmojiEventsIcon/></div>*/}
......@@ -72,7 +73,7 @@ export default function RoomToolsBar (props: any) {
? <div className="tool-btn" onClick={allMuteOff}><RecordVoiceOverIcon/></div>
: <div onClick={allMuteOn} className="tool-btn"><VoiceOverOffIcon/></div>
}
{currentTool == TOOL_TYPE.WHITEBOARD
{currentTool === TOOL_TYPE.WHITEBOARD
? <div className="tool-btn" onClick={changeTool}><ImportContacts/></div>
: <div onClick={changeTool} className="tool-btn"><Category/></div>
}
......
......@@ -5,7 +5,6 @@ import Button from './custom-button';
import FormSelect from './form-select';
import SpeakerVolume from './volume/speaker';
import useSettingControl from '../hooks/use-setting-control';
import { usePlatform } from '../containers/platform-container';
const useStyles = makeStyles ({
......@@ -34,7 +33,7 @@ export default function (props: SettingProps) {
setCamera,
setMicrophone,
setSpeaker,
volume,
/*volume,*/
speakerVolume,
setSpeakerVolume,
save,
......@@ -77,7 +76,7 @@ export default function (props: SettingProps) {
</div>
<div className="position-content flex-direction-column">
<FormControl className={classes.formControl}>
<FormSelect
<FormSelect
Label={"Camera"}
value={camera}
onChange={changeCamera}
......@@ -85,7 +84,7 @@ export default function (props: SettingProps) {
/>
</FormControl>
<FormControl className={classes.formControl}>
<FormSelect
<FormSelect
Label={"Microphone"}
value={microphone}
onChange={changeMicrophone}
......@@ -94,7 +93,7 @@ export default function (props: SettingProps) {
<MicrophoneVolume />
</FormControl>
<FormControl className={classes.formControl}>
<FormSelect
<FormSelect
Label={"Speaker"}
value={speaker}
onChange={changeSpeaker}
......@@ -116,4 +115,4 @@ export default function (props: SettingProps) {
</div>
</div>
)
}
\ No newline at end of file
}
import React, { useEffect, useRef, useState } from 'react';
import './toast.scss';
import {useGlobalState} from '../containers/root-container';
import { isEmpty } from 'lodash';
// import { isEmpty } from 'lodash';
export interface SnackbarMessage {
message: string;
......@@ -30,6 +30,7 @@ export default function ConsecutiveSnackbars({
timerRef.current = null;
}, duration);
}
// eslint-disable-next-line
}, [messages]);
useEffect(() => {
......@@ -40,11 +41,12 @@ export default function ConsecutiveSnackbars({
})
setMessages([...queueRef.current]);
}
// eslint-disable-next-line
}, [globalState.toast]);
return (
<div className="notice-message-container">
{messages.map((message: any, idx: number) =>
{messages.map((message: any, idx: number) =>
<div key={`${idx}${message.key}`} className={"custom-toast"}>
<div className="toast-container">
<span className="text">{message.message}</span>
......
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useState } from 'react';
import './toast.scss';
import {useGlobalState} from '../containers/root-container';
import { isEmpty } from 'lodash';
// import {useGlobalState} from '../containers/root-container';
// import { isEmpty } from 'lodash';
import {roomStore} from "../stores/room";
......@@ -25,7 +25,8 @@ export default function UserStars({id, streamID}: UserStarsProps) {
}
}
// setStar()
}, [roomStore.state.userStars]);
// eslint-disable-next-line
}, [roomStore.state.userStars, streamID]);
......
import React, {useRef, useEffect, useMemo, useState} from 'react';
import React, {useRef, useEffect, useMemo} from 'react';
import Icon from './icon';
import './video-player.scss';
import { AgoraElectronStream, StreamType, nativeRTCClient as nativeClient } from '../utils/agora-electron-client';
......@@ -8,7 +8,7 @@ import ArrowDownwardIcon from '@material-ui/icons/ArrowDownward';
import {makeStyles} from '@material-ui/core/styles';
import {roomStore} from "../stores/room";
import BuildIcon from '@material-ui/icons/Build';
import {eventBus} from "../stores/EventBus";
// import {eventBus} from "../stores/EventBus";
// import StarIcon from '@material-ui/icons/Star';
// import EmojiEventsOutlinedIcon from '@material-ui/icons/EmojiEventsOutlined';
import UserStars from './user-stars';
......@@ -108,6 +108,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
const AgoraRtcEngine = useMemo(() => {
return nativeClient.rtcEngine;
// eslint-disable-next-line
}, [nativeClient.rtcEngine]);
useEffect(() => {
......@@ -168,11 +169,13 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
}
}
}
// eslint-disable-next-line
}, [domId, stream, AgoraRtcEngine]);
useEffect(() => {
if (platform === 'web') {
if (!stream || !domId || lockPlay.current && stream.isPlaying()) return;
if (!stream || !domId || (lockPlay.current && stream.isPlaying())) return;
lockPlay.current = true;
/*const playFn = () => {
if (reloadStreamTimer) {
......@@ -221,6 +224,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
local && stream && stream.close();
}
}
// eslint-disable-next-line
}, [domId, stream]);
/*
......@@ -277,6 +281,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
console.log("[agora-electron] muteLocalAudioStream(true); ", res);
}
}
// eslint-disable-next-line
}, [stream, audio, AgoraRtcEngine]);
useEffect(() => {
......@@ -319,6 +324,7 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
console.log("[agora-electron] muteLocalVideoStream(true); ", res);
}
}
// eslint-disable-next-line
}, [stream, video, AgoraRtcEngine]);
const onAudioClick = (evt: any) => {
......@@ -350,16 +356,16 @@ const VideoPlayer: React.FC<VideoPlayerProps> = ({
handleClose('close', streamID);
}
}
const addStar = (evt: any) => {
if (me.role != 'teacher') {
return
}
eventBus.emit('showAddStartDialog', {uid: id});
}
const resumeStream = (evt: any) => {
stateError.current = false;
stream.resume()
}
// const addStar = (evt: any) => {
// if (me.role != 'teacher') {
// return
// }
// eventBus.emit('showAddStartDialog', {uid: id});
// }
// const resumeStream = (evt: any) => {
// stateError.current = false;
// stream.resume()
// }
const me = useRoomState().me;
const teacherId = useRoomState().course.teacherId;
......@@ -372,7 +378,7 @@ return (
{preview ? null :
account ?
<>
{ streamID > 0 && id != teacherId?
{ streamID > 0 && id !== teacherId?
<>
<UserStars id={id} streamID={streamID}></UserStars>
<div className="hands-wrapper">
......@@ -399,7 +405,7 @@ return (
<>
{id != roomStore.state.course.teacherId
{id !== roomStore.state.course.teacherId
?
<>
{/*<EmojiEventsOutlinedIcon onClick={addStar} className={style.emojiEvent}></EmojiEventsOutlinedIcon>*/}
......
import React, { useRef, useEffect, useState, useLayoutEffect } from 'react';
import React, { useRef, useEffect, useState } from 'react';
import VideoPlayer from './video-player';
// import Icon from './icon';
import {ExpandMore, ExpandLess} from '@material-ui/icons';
......@@ -7,8 +7,8 @@ import useStream from '../hooks/use-streams';
import { AgoraMediaStream } from '../utils/types';
import {STAGE_NUM} from "../utils/consts";
import MemberHolder from "./member-holder";
import { Dialog, Button, DialogContent, DialogActions, TextField, DialogContentText, DialogTitle } from '@material-ui/core';
import { roomStore } from '../stores/room';
// import { Dialog, Button, DialogContent, DialogActions, TextField, DialogContentText, DialogTitle } from '@material-ui/core';
// import { roomStore } from '../stores/room';
function VideoShowList() {
......
......@@ -32,6 +32,7 @@ export default function ContinuousSlider(props: SliderProps) {
useEffect(() => {
props.onChange(value);
// eslint-disable-next-line
}, [value]);
return (
......@@ -42,4 +43,4 @@ export default function ContinuousSlider(props: SliderProps) {
</div>
</div>
);
}
\ No newline at end of file
}
import React, { useRef } from 'react';
import React from 'react';
import Icon from '../icon';
import { roomStore } from '../../stores/room';
import { whiteboard } from '../../stores/whiteboard';
import moment from 'moment';
import { globalStore } from '../../stores/global';
import { getOSSUrl } from '../../utils/helper';
// import { roomStore } from '../../stores/room';
// import { whiteboard } from '../../stores/whiteboard';
// import moment from 'moment';
// import { globalStore } from '../../stores/global';
// import { getOSSUrl } from '../../utils/helper';
interface ControlItemProps {
name: string
onClick: (evt: any, name: string) => void
......@@ -58,8 +58,8 @@ export default function Control({
role,
notice,
}: ControlProps) {
const lock = useRef<boolean>(false);
// const lock = useRef<boolean>(false);
/*
const canStop = () => {
const timeMoment = moment(whiteboard.state.startTime).add(15, 'seconds');
if (+timeMoment >= +Date.now()) {
......@@ -70,8 +70,9 @@ export default function Control({
return false;
}
return true;
}
}*/
/*
const onRecordButtonClick = (evt: any, type: string) => {
handleRecording(evt, type)
.then(() => {}).catch(console.warn);
......@@ -124,7 +125,7 @@ export default function Control({
}
}
}
*/
return (
<div className="controls-container">
<div className="interactive">
......
import React from 'react';
import OSS from "ali-oss";
// import OSS from "ali-oss";
import uuidv4 from 'uuid/v4';
import { PPTProgressListener, UploadManager } from "../../../utils/upload-manager";
import { PptKind, Room } from "white-web-sdk";
import {ossConfig, ossClient, resolveFileInfo, getOssClient} from '../../../utils/helper';
import { Room } from "white-web-sdk";
import {ossConfig, resolveFileInfo, getOssClient} from '../../../utils/helper';
import { whiteboard } from '../../../stores/whiteboard';
export type UploadBtnProps = {
......@@ -18,6 +18,7 @@ export const UploadBtn: React.FC<UploadBtnProps> = ({
room, uuid, roomToken,
onProgress, onFailure
}) => {
/*
const uploadDynamic = async (event: any) => {
try {
const file = event.currentTarget.files[0];
......@@ -60,7 +61,7 @@ export const UploadBtn: React.FC<UploadBtnProps> = ({
console.warn(err)
}
}
*/
const uploadImage = async (event: any) => {
try {
const file = event.currentTarget.files[0];
......
import React, { useEffect } from 'react';
import Icon from '../components/icon';
import _, {isFunction} from 'lodash';
import _ from 'lodash';
import { useLocation } from 'react-router';
export interface IPlatformContext {
......@@ -43,7 +43,7 @@ export const PlatformContainer: React.FC<React.ComponentProps<any>> = ({ childre
const handleClick = (type: string) => {
if (!ipc) return;
switch (type) {
case 'minimum': {
ipc.send('minimum');
......@@ -124,4 +124,4 @@ export const PlatformContainer: React.FC<React.ComponentProps<any>> = ({ childre
{children}
</PlatformContext.Provider>
)
}
\ No newline at end of file
}
......@@ -6,7 +6,7 @@ import { useHistory, useLocation } from 'react-router-dom';
import { resolveMessage, resolvePeerMessage, resolveChannelAttrs, jsonParse } from '../utils/helper';
import GlobalStorage from '../utils/custom-storage';
import {endPoint, goHome} from "../services/agora-end-points";
import {Map as immuMap} from "immutable";
// import {Map as immuMap} from "immutable";
export type IRootProvider = {
globalState: GlobalState
......@@ -29,7 +29,7 @@ function useObserver<T>(store: IObserver<T>) {
return () => {
store.unsubscribe();
}
}, []);
}, [store]);
return state;
}
......@@ -114,7 +114,7 @@ export const RootProvider: React.FC<any> = ({children}) => {
}).catch(console.warn);
});
rtmClient.on("AttributesUpdated", (attributes: object) => {
if (Object.keys(attributes).length == 0) {
if (Object.keys(attributes).length === 0) {
globalStore.showToast({
type: 'rtmClient',
message: 'teacher close classroom'
......@@ -165,6 +165,7 @@ export const RootProvider: React.FC<any> = ({children}) => {
return () => {
rtmClient.removeAllListeners();
}
// eslint-disable-next-line
}, [roomStore.state.rtm.joined]);
const location = useLocation();
......@@ -199,7 +200,7 @@ export const RootProvider: React.FC<any> = ({children}) => {
window.whiteboard = whiteboardState;
//@ts-ignore
window.store = globalStore;
// eslint-disable-next-line
}, [value, location]);
return (
......
......@@ -42,7 +42,7 @@ export default function useChatText () {
setValue(evt.target.value.slice(0, 100));
}
const list = useMemo(() => {
if (!roomState.me.uid || !roomState.rtc.users.count() && !roomState.rtc.localStream) return [];
if (!roomState.me.uid || !roomState.rtc.users.count() /*&& !roomState.rtc.localStream*/) return [];
const my = roomState.users.get(roomState.me.uid);
const users = [];
if (my) {
......@@ -55,7 +55,7 @@ export default function useChatText () {
}
}
return users.filter((user: AgoraUser) => user.role === 'student');
}, [roomState.me.uid, roomState.rtc.users, roomState.users, roomState.rtc.localStream]);
}, [roomState.me.uid, roomState.rtc.users, roomState.users/*, roomState.rtc.localStream*/]);
return {
list,
......@@ -66,4 +66,4 @@ export default function useChatText () {
handleChange,
roomName
}
}
\ No newline at end of file
}
......@@ -15,19 +15,19 @@ export default function useSettingControl () {
const cameraList = useMemo(() => {
return devices
.filter((it: Device) =>
.filter((it: Device) =>
it.kind === 'videoinput');
}, [devices]);
const microphoneList = useMemo(() => {
return devices
.filter((it: Device) =>
.filter((it: Device) =>
it.kind === 'audioinput');
}, [devices]);
const speakerList = useMemo(() => {
return devices
.filter((it: Device) =>
.filter((it: Device) =>
it.kind === 'audiooutput');
}, [devices]);
......@@ -43,13 +43,13 @@ export default function useSettingControl () {
const [speakerVolume, setSpeakerVolume] = useState<number>(mediaDevice.speakerVolume);
const [volume, setVolume] = useState<number>(0);
let mounted = false;
const mounted = useRef<boolean>(false);
useEffect(() => {
const rtcClient: AgoraWebClient | AgoraElectronClient = roomStore.rtcClient;
if (!platform || !rtcClient) return;
if (platform === 'web' && !mounted) {
if (platform === 'web' && !mounted.current) {
const webClient = rtcClient as AgoraWebClient;
const onChange = async () => {
const devices: Device[] = await webClient.getDevices();
......@@ -62,13 +62,13 @@ export default function useSettingControl () {
window.addEventListener('devicechange', onChange);
onChange().then(() => {
}).catch(console.warn);
mounted = true;
mounted.current = true;
return () => {
window.removeEventListener('devicechange', onChange);
}
}
if (platform === 'electron' && !mounted) {
if (platform === 'electron' && !mounted.current) {
const nativeClient = rtcClient as AgoraElectronClient;
const onChange = async () => {
......@@ -100,7 +100,7 @@ export default function useSettingControl () {
nativeClient.on('videodevicestatechanged', onChange);
nativeClient.on('audiodevicestatechanged', onChange);
mounted = true;
mounted.current = true;
return () => {
nativeClient.off('videodevicestatechanged', onChange);
nativeClient.off('audiodevicestatechanged', onChange);
......@@ -199,7 +199,7 @@ export default function useSettingControl () {
console.log('startplayback off result', nativeClient.rtcEngine.stopAudioPlaybackDeviceTest());
}
}
}, [stream]);
}, [stream, platform]);
const PreviewPlayer = useCallback(() => {
if (!stream) return null;
......@@ -259,4 +259,4 @@ export default function useSettingControl () {
MicrophoneVolume,
save: handleSave,
}
}
\ No newline at end of file
}
import { useMemo } from 'react';
import { SHARE_ID } from '../utils/agora-rtc-client';
import _ from 'lodash';
// import _ from 'lodash';
import { roomStore } from '../stores/room';
import { useRoomState } from '../containers/root-container';
import {STAGE_NUM} from "../utils/consts";
// import {STAGE_NUM} from "../utils/consts";
type StreamValue ={
teacher: any
......@@ -132,7 +132,7 @@ export default function useStream () {
const studentsOrder = [...roomStore.state.studentsOrder] || [];
// exclude teacher and me
let studentIds = peerUsers.filter((it: number) => studentsOrder.includes(it) && `${it}` !== `${teacherUid}` && `${it}` !== `${me.uid}` && `${it}` !== `${SHARE_ID}`);
if (me.role != 'teacher') {
if (me.role !== 'teacher') {
studentIds = studentIds.add(+me.uid);
}
......@@ -150,11 +150,11 @@ export default function useStream () {
const sids: any = [];
let orderIdx = 0;
for (const ouid of studentsOrder) {
if (ouid == 0) {
if (ouid === 0) {
sids.push(0)
} else {
// find in peer
const uid = studentIds.find((it: number) => `${ouid}` == `${it}`);
const uid = studentIds.find((it: number) => `${ouid}` === `${it}`);
if (uid) {
sids.push(uid);
roomStore.releaseWaitStreamHandle(+uid);
......@@ -193,11 +193,11 @@ export default function useStream () {
// capture all remote streams
for (let studentId of /*studentIds*/sids) {
// console.log('*****************', studentId)
if (studentId == undefined) {
if (studentId === undefined) {
continue
}
if (studentId == 0) {
if (studentId === 0) {
const _tmpStream = {
account: '空闲',
streamID: studentId,
......@@ -220,7 +220,7 @@ export default function useStream () {
continue
}
if (me.role === 'student' && +me.uid == studentId) {
if (me.role === 'student' && +me.uid === studentId) {
if (myAttr && roomState.rtc.localStream) {
// console.log('use local stream')
const _tmpStream = {
......@@ -267,14 +267,14 @@ export default function useStream () {
}
userAttrs.forEach((v, k) => {
if (!sids.includes(+v.uid)) {
if (`${v.uid}` != `${teacherUid}`) {
if (`${v.uid}` !== `${teacherUid}`) {
const s: any = {
streamID: +v.uid,
account: v.account,
video: v.video,
audio: v.audio, // roomState.course.muteAudio ? 0 : v.audio,
}
if (`${me.uid}` == `${v.uid}`) {
if (`${me.uid}` === `${v.uid}`) {
s.local = true;
}
studentStreams.push(s)
......@@ -283,6 +283,7 @@ export default function useStream () {
})
// console.log('studentStreams', studentStreams);
return studentStreams;
// eslint-disable-next-line
}, [
// course,
me.uid,
......@@ -415,6 +416,7 @@ export default function useStream () {
}
}
return null;
// eslint-disable-next-line
}, [
course,
me.uid,
......@@ -458,7 +460,7 @@ export default function useStream () {
if (audio) {
await roomStore.mute(targetUid, 'audio');
} else {
if (me.role == 'student' && roomStore.state.course.muteAudio) {
if (me.role === 'student' && roomStore.state.course.muteAudio) {
return
}
await roomStore.unmute(targetUid, 'audio');
......
......@@ -299,6 +299,27 @@
background-repeat: no-repeat;
opacity: 0.9;
}
.permission-placeholder{
border-top-left-radius: 8px;
border-bottom-left-radius: 8px;
display: flex;
flex: 1 1;
position: absolute;
height: 100%;
width: 100%;
}
.permission-placeholder::before {
content: ' ';
background-image: url(./assets/WechatIMG77.png);
background-position: center;
background-repeat: no-repeat;
//opacity: 0.9;
flex: 1 1;
background-color: #DBE2E5;
justify-content: center;
box-sizing: border-box;
background-size: contain;
}
.media-board.panel {
pointer-events: none;
......
This diff is collapsed.
import React, {useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import React, {useMemo, useRef} from 'react';
// import VideoMarquee from '../../components/video-marquee';
import MediaBoard from '../../components/mediaboard';
// import Roomboard from '../../components/roomboard';
import './small-class.scss';
import CourseWareFrame from "../../components/courseware-frame";
import VideoShowList from "../../components/video-stage-list";
import {ToolsSwitcherController} from "../../components/tools-switcher-controller";
// import {ToolsSwitcherController} from "../../components/tools-switcher-controller";
import {roomStore} from "../../stores/room";
import {TOOL_TYPE} from "../../utils/types";
// import {platform} from "../../utils/platform";
......@@ -18,19 +18,19 @@ import Icon from "../../components/icon";
export default function SmallClass() {
const [tool, setTool] = useState(true);
// const [tool, setTool] = useState(true);
const roomState = useRoomState();
const changeTool = async () => {
/*const changeTool = async () => {
console.log(roomStore.state.course.currentTool);
if (roomStore.state.course.currentTool == TOOL_TYPE.WHITEBOARD) {
await roomStore.setCurrentTool(TOOL_TYPE.COURSE_WARE)
} else {
await roomStore.setCurrentTool(TOOL_TYPE.WHITEBOARD)
}
}
}*/
const {currentTool} = useMemo(() => {
return {
currentTool: roomStore.state.course.currentTool
currentTool: roomState.course.currentTool
}
}, [roomState]);
......@@ -84,9 +84,7 @@ export default function SmallClass() {
*/
}
useEffect(() => {
}, [roomStore.state.course.currentTool]);
return (
<div className="room-container">
{/*<VideoMarquee />*/}
......@@ -96,16 +94,21 @@ export default function SmallClass() {
{/* changeTool();*/}
{/*}}/> : null}*/}
{currentTool == TOOL_TYPE.WHITEBOARD
{currentTool === TOOL_TYPE.WHITEBOARD
? <MediaBoard />
: <CourseWareFrame></CourseWareFrame>}
<Icon
data='hands_up'
onClick={handleClick}
className={`items hands_up ${false ? 'active' : ''}`}
/>
{
roomStore.state.me.role !== 'teacher'
? <Icon
data='hands_up'
onClick={handleClick}
className={`items hands_up ${false ? 'active' : ''}`}
/>
: null
}
{/*{ roomStore.state.me.role == 'teacher' ? <Roomboard currentActive={'media'} /> : null}*/}
</div>
......
......@@ -98,11 +98,11 @@ function HomePage() {
setClasses([])
return
}
// setLoading(true);
setLoading(true);
globalStore.showLoading();
const data = await endPoint.fetchClasses(session.yourName);
console.log(data);
// setLoading(false);
setLoading(false);
globalStore.stopLoading();
setSessionInfo({
...session,
......@@ -185,9 +185,9 @@ function HomePage() {
// console.log(1111111111111, location );
const params = new URLSearchParams(location.search);
let token:any = params.get('token');
let isDebug = params.get('debug') && params.get('debug') == '1' ? true : false;
let hasLogin = params.get('login') && params.get('login') == '1' ? true : false;
let isLocal = params.get('isLocal') && params.get('isLocal') == '1' ? true : false;
let isDebug = params.get('debug') && params.get('debug') === '1' ? true : false;
let hasLogin = params.get('login') && params.get('login') === '1' ? true : false;
let isLocal = params.get('isLocal') && params.get('isLocal') === '1' ? true : false;
console.log('token', token)
console.log('isDebug', isDebug)
console.log('hasLogin', hasLogin)
......@@ -196,11 +196,11 @@ function HomePage() {
endPoint.setUserToken(token);
const tokenParts = token.split('.')
token = tokenParts[1];
token = token.replace(/[\+]/g, '-');
token = token.replace(/[+]/g, '-');
token = token.replace(/[/]/g, '_');
const eqc = token.length % 4;
const ea: any = [];
if ( eqc != 0 ) {
if ( eqc !== 0 ) {
ea.length = 4 - eqc;
token = `${token}${Array.from(ea).fill('=').join('')}`
}
......
......@@ -6,6 +6,8 @@ import Home from './home';
import DeviceTest from './device-test';
import { RoomPage } from './classroom';
import Loading from '../components/loading';
import Permission from '../components/permission';
import Toast from '../components/toast';
import '../icons.scss';
import { PlatformContainer } from '../containers/platform-container';
......@@ -23,6 +25,7 @@ export default function () {
<PlatformContainer>
<RootProvider>
<Loading />
<Permission />
<Toast />
<Route exact path="/">
<Home />
......@@ -53,4 +56,4 @@ export default function () {
</CustomBrowserRouter>
</ThemeContainer>
)
}
\ No newline at end of file
}
......@@ -147,7 +147,7 @@ class ReplayStore {
phase,
isPlaying,
}
this.commit(this.state);
}
......@@ -160,7 +160,7 @@ class ReplayStore {
this.commit(this.state);
}
async joinRoom(_uuid: string) {
return await WhiteboardAPI.joinRoom(_uuid);
}
......@@ -201,9 +201,9 @@ export const Replay: React.FC<{}> = () => {
const player = useMemo(() => {
if (!store.state || !store.state.player) return null;
return store.state.player as Player;
// eslint-disable-next-line
}, [store.state]);
const handlePlayerClick = () => {
if (!store.state || !player) return;
......@@ -267,6 +267,7 @@ export const Replay: React.FC<{}> = () => {
if (!startTime || !endTime) return 0;
const _duration = Math.abs(+startTime - +endTime);
return _duration;
// eslint-disable-next-line
}, [startTime, endTime]);
const lock = useRef<boolean>(false);
......@@ -275,6 +276,7 @@ export const Replay: React.FC<{}> = () => {
return () => {
lock.current = true;
}
// eslint-disable-next-line
}, []);
useEffect(() => {
......@@ -338,6 +340,7 @@ export const Replay: React.FC<{}> = () => {
window.removeEventListener('resize', onWindowResize);
window.removeEventListener('keydown', onWindowResize);
}
// eslint-disable-next-line
}, []);
const totalTime = useMemo(() => {
......@@ -358,12 +361,14 @@ export const Replay: React.FC<{}> = () => {
return (
<div className="player-cover">
{player.phase === PlayerPhase.Buffering ? <Progress title={"loading..."} />: null}
{player.phase === PlayerPhase.Pause || player.phase === PlayerPhase.Ended || player.phase === PlayerPhase.WaitingFirstFrame ?
{player.phase === PlayerPhase.Pause || player.phase === PlayerPhase.Ended || player.phase === PlayerPhase.WaitingFirstFrame ?
<div className="play-btn" onClick={handlePlayerClick}></div> : null}
</div>
)
// eslint-disable-next-line
}, [player]);
return (
<div className="replay">
<div className={`player-container`} >
......@@ -416,4 +421,4 @@ export const Replay: React.FC<{}> = () => {
</div>
</div>
)
}
\ No newline at end of file
}
......@@ -46,6 +46,7 @@ export interface RoomParams {
export function goHome(history: any){
GlobalStorage.clear('agora_room');
window.onbeforeunload = null;
window.location.href = 'http://iteachabc.com'
}
export function goLogin(){
......
......@@ -12,4 +12,4 @@ module.exports = function (app) {
// changeOrigin: true,
// })
// )
}
\ No newline at end of file
}
......@@ -2,6 +2,7 @@ import {Subject} from 'rxjs';
export type GlobalState = {
loading: boolean
permission: boolean
toast: {
type: string
message: string
......@@ -31,6 +32,7 @@ export class Root {
public state: GlobalState;
public readonly defaultState: GlobalState = {
loading: false,
permission: false,
toast: {
type: '',
message: '',
......@@ -198,6 +200,22 @@ export class Root {
}
this.commit(this.state);
}
showPermission () {
this.state = {
...this.state,
permission: true
}
this.commit(this.state);
}
stopPermission () {
this.state = {
...this.state,
permission: false
}
this.commit(this.state);
}
}
export const globalStore = new Root();
......
This diff is collapsed.
......@@ -37,7 +37,7 @@ export interface SceneResource {
}
const pathName = (path: string): string => {
const reg = /\/([^\/]*)\//g;
const reg = /\/([^/]*)\//g;
reg.exec(path);
if (RegExp.$1 === "aria") {
return "";
......
......@@ -14,7 +14,7 @@ if (AgoraRtcEngine) {
AgoraRtcEngine.setVideoProfile(43, false);
}
const SHARE_ID = 7;
const SHARE_ID = 0;
export interface Stream {
uid: number
......@@ -31,10 +31,12 @@ export class AgoraElectronStream {
public stream: Stream;
public playing: boolean = false;
private domID: string;
public uid: number;
constructor(
public uid: number = uid,
uid: number,
public readonly type: StreamType = StreamType.remote,
) {
this.uid = uid;
this.domID = '';
this.stream = {
uid: this.uid,
......
......@@ -46,7 +46,7 @@ const clientEvents: string[] = [
export const APP_ID = process.env.REACT_APP_AGORA_APP_ID as string;
export const APP_TOKEN = process.env.REACT_APP_AGORA_APP_TOKEN as string;
export const ENABLE_LOG = process.env.REACT_APP_AGORA_LOG as string === "true";
export const SHARE_ID = 65535;
export const SHARE_ID = 0;
const BindEventMap: any = {};
class AgoraRTCClient {
......
......@@ -121,7 +121,11 @@ export default class AgoraRTMClient {
async login (uid: string, token?: string) {
this._channelAttrsKey = uid;
await this._client.login({uid, token});
try{
await this._client.login({uid, token});
} catch (e) {
}
this._client.on("ConnectionStateChanged", (newState: string, reason: string) => {
this._bus.emit("ConnectionStateChanged", {newState, reason});
});
......
......@@ -120,6 +120,7 @@ export class RecordOperator {
if (typeof res.resourceId === "string") {
this.resourceId = res.resourceId;
} else {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'acquire recording failed',
......@@ -129,6 +130,7 @@ export class RecordOperator {
}
}
public async release(): Promise<void> {
this.resourceId = undefined;
this.recordId = undefined;
......@@ -137,6 +139,7 @@ export class RecordOperator {
public async start(): Promise<any> {
if (this.resourceId === undefined) {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'start recording failed',
......@@ -164,6 +167,7 @@ export class RecordOperator {
if (typeof res.sid === "string") {
this.recordId = res.sid;
} else {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'start recording failed',
......@@ -176,6 +180,7 @@ export class RecordOperator {
public async stop(): Promise<any> {
if (this.resourceId === undefined) {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'stop recording failed',
......@@ -184,6 +189,7 @@ export class RecordOperator {
}
}
if (this.recordId === undefined) {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'stop recording failed',
......@@ -216,6 +222,7 @@ export class RecordOperator {
public async query(): Promise<any> {
if (this.resourceId === undefined) {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'query recording failed',
......@@ -224,6 +231,7 @@ export class RecordOperator {
}
}
if (this.recordId === undefined) {
// eslint-disable-next-line
throw {
recordingErr: {
message: 'query recording failed',
......
......@@ -341,6 +341,10 @@ export function resolveChannelAttrs(json: object) {
});
}
for (let student of students) {
student.stars = +student.stars;
if (!student.stars || isNaN(student.stars)) {
student.stars = 0;
}
accounts.push({
role: 'student',
account: student.account,
......
......@@ -27,8 +27,11 @@ export interface AgoraMediaStream {
export class AgoraStream {
constructor(
// eslint-disable-next-line
public readonly stream: any = stream,
// eslint-disable-next-line
public readonly streamID: number = streamID,
// eslint-disable-next-line
public readonly local: boolean = local,
) {
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment