Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
live
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
liujiaxin
live
Commits
a4e226a0
Commit
a4e226a0
authored
Apr 09, 2020
by
liujiaxin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:添加检测用户是否开启音视频权限功能
parent
788c9a76
Changes
41
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
41 changed files
with
580 additions
and
324 deletions
+580
-324
package.json
package.json
+7
-1
WechatIMG77.png
src/assets/WechatIMG77.png
+0
-0
add-stars-btn.tsx
src/components/add-stars-btn.tsx
+5
-5
courseware-frame.tsx
src/components/courseware-frame.tsx
+11
-9
room.tsx
src/components/dialog/room.tsx
+1
-1
hands-up-icon.tsx
src/components/hands-up-icon.tsx
+6
-6
mediaboard.tsx
src/components/mediaboard.tsx
+14
-6
member-holder.tsx
src/components/member-holder.tsx
+13
-8
nav.tsx
src/components/nav.tsx
+5
-2
permission.tsx
src/components/permission.tsx
+65
-0
room-tools-bar.tsx
src/components/room-tools-bar.tsx
+14
-13
setting-card.tsx
src/components/setting-card.tsx
+5
-6
toast.tsx
src/components/toast.tsx
+4
-2
user-stars.tsx
src/components/user-stars.tsx
+5
-4
video-player.tsx
src/components/video-player.tsx
+21
-15
video-stage-list.tsx
src/components/video-stage-list.tsx
+3
-3
speaker.tsx
src/components/volume/speaker.tsx
+2
-1
control.tsx
src/components/whiteboard/control.tsx
+11
-10
upload-btn.tsx
src/components/whiteboard/upload/upload-btn.tsx
+5
-4
platform-container.tsx
src/containers/platform-container.tsx
+3
-3
root-container.tsx
src/containers/root-container.tsx
+5
-4
use-chat-text.ts
src/hooks/use-chat-text.ts
+3
-3
use-setting-control.tsx
src/hooks/use-setting-control.tsx
+10
-10
use-streams.ts
src/hooks/use-streams.ts
+13
-11
icons.scss
src/icons.scss
+21
-0
index.tsx
src/pages/classroom/index.tsx
+169
-115
small-class.tsx
src/pages/classroom/small-class.tsx
+17
-14
home.tsx
src/pages/home.tsx
+7
-7
index.tsx
src/pages/index.tsx
+4
-1
replay.tsx
src/pages/replay.tsx
+10
-5
agora-end-points.ts
src/services/agora-end-points.ts
+1
-0
setupProxy.js
src/setupProxy.js
+1
-1
global.ts
src/stores/global.ts
+18
-0
room.ts
src/stores/room.ts
+75
-49
whiteboard.ts
src/stores/whiteboard.ts
+1
-1
agora-electron-client.ts
src/utils/agora-electron-client.ts
+4
-2
agora-rtc-client.ts
src/utils/agora-rtc-client.ts
+1
-1
agora-rtm-client.ts
src/utils/agora-rtm-client.ts
+5
-1
api.ts
src/utils/api.ts
+8
-0
helper.ts
src/utils/helper.ts
+4
-0
types.ts
src/utils/types.ts
+3
-0
No files found.
package.json
View file @
a4e226a0
...
...
@@ -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"
:
[
...
...
src/assets/WechatIMG77.png
0 → 100644
View file @
a4e226a0
130 KB
src/components/add-stars-btn.tsx
View file @
a4e226a0
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
})
...
...
src/components/courseware-frame.tsx
View file @
a4e226a0
import
React
,
{
use
Ref
,
useEffect
,
useMemo
,
useState
}
from
'
react
'
;
import
Icon
from
'
./icon
'
;
import
React
,
{
use
Effect
,
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
()
=>
{
s
rc
=
'
about:blank
'
s
etSrc
(
'
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
>
)
}
...
...
src/components/dialog/room.tsx
View file @
a4e226a0
...
...
@@ -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
...
...
src/components/hands-up-icon.tsx
View file @
a4e226a0
import
React
,
{
use
Effect
,
useMemo
,
useRef
,
useState
}
from
'
react
'
;
import
React
,
{
use
Memo
}
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
(
...
...
src/components/mediaboard.tsx
View file @
a4e226a0
...
...
@@ -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
}
/>
...
...
src/components/member-holder.tsx
View file @
a4e226a0
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
(
...
...
src/components/nav.tsx
View file @
a4e226a0
...
...
@@ -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
);
...
...
src/components/permission.tsx
0 → 100644
View file @
a4e226a0
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
)
}
src/components/room-tools-bar.tsx
View file @
a4e226a0
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
>
}
...
...
src/components/setting-card.tsx
View file @
a4e226a0
...
...
@@ -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
}
src/components/toast.tsx
View file @
a4e226a0
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
>
...
...
src/components/user-stars.tsx
View file @
a4e226a0
import
React
,
{
useEffect
,
use
Ref
,
use
State
}
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
]);
...
...
src/components/video-player.tsx
View file @
a4e226a0
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>*/
}
...
...
src/components/video-stage-list.tsx
View file @
a4e226a0
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
()
{
...
...
src/components/volume/speaker.tsx
View file @
a4e226a0
...
...
@@ -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
}
src/components/whiteboard/control.tsx
View file @
a4e226a0
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"
>
...
...
src/components/whiteboard/upload/upload-btn.tsx
View file @
a4e226a0
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
];
...
...
src/containers/platform-container.tsx
View file @
a4e226a0
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
}
src/containers/root-container.tsx
View file @
a4e226a0
...
...
@@ -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
(
...
...
src/hooks/use-chat-text.ts
View file @
a4e226a0
...
...
@@ -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
}
src/hooks/use-setting-control.tsx
View file @
a4e226a0
...
...
@@ -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
}
src/hooks/use-streams.ts
View file @
a4e226a0
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
'
);
...
...
src/icons.scss
View file @
a4e226a0
...
...
@@ -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
;
...
...
src/pages/classroom/index.tsx
View file @
a4e226a0
This diff is collapsed.
Click to expand it.
src/pages/classroom/small-class.tsx
View file @
a4e226a0
import
React
,
{
use
Effect
,
useLayoutEffect
,
useMemo
,
useRef
,
useState
}
from
'
react
'
;
import
React
,
{
use
Memo
,
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
:
roomSt
ore
.
st
ate
.
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
>
...
...
src/pages/home.tsx
View file @
a4e226a0
...
...
@@ -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
(
''
)}
`
}
...
...
src/pages/index.tsx
View file @
a4e226a0
...
...
@@ -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
}
src/pages/replay.tsx
View file @
a4e226a0
...
...
@@ -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
}
src/services/agora-end-points.ts
View file @
a4e226a0
...
...
@@ -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
(){
...
...
src/setupProxy.js
View file @
a4e226a0
...
...
@@ -12,4 +12,4 @@ module.exports = function (app) {
// changeOrigin: true,
// })
// )
}
\ No newline at end of file
}
src/stores/global.ts
View file @
a4e226a0
...
...
@@ -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
();
...
...
src/stores/room.ts
View file @
a4e226a0
This diff is collapsed.
Click to expand it.
src/stores/whiteboard.ts
View file @
a4e226a0
...
...
@@ -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
""
;
...
...
src/utils/agora-electron-client.ts
View file @
a4e226a0
...
...
@@ -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
,
...
...
src/utils/agora-rtc-client.ts
View file @
a4e226a0
...
...
@@ -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
{
...
...
src/utils/agora-rtm-client.ts
View file @
a4e226a0
...
...
@@ -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
});
});
...
...
src/utils/api.ts
View file @
a4e226a0
...
...
@@ -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
'
,
...
...
src/utils/helper.ts
View file @
a4e226a0
...
...
@@ -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
,
...
...
src/utils/types.ts
View file @
a4e226a0
...
...
@@ -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
,
)
{
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment