diff --git a/src/infra/capabilities/containers/screen-share/index.css b/src/infra/capabilities/containers/screen-share/index.css index 016c367b9..6e8c787bf 100644 --- a/src/infra/capabilities/containers/screen-share/index.css +++ b/src/infra/capabilities/containers/screen-share/index.css @@ -4,15 +4,21 @@ } .local-screen-share-container { - display: flex; - justify-content: center; position: absolute; width: 100%; - top: 5px; + height: 100%; z-index: 2; pointer-events: none; } - +.local-screen-share-container .stop-button_wrap { + width: 108px; + height: 30; + position: absolute; + top: 5px; + left: 50%; + transform: translateX(-50%); + z-index: 999; +} .local-screen-share-container .stop-button { font-size: 12px; width: 100%; diff --git a/src/infra/capabilities/containers/screen-share/index.tsx b/src/infra/capabilities/containers/screen-share/index.tsx index 7b26566b6..cd51d0b62 100644 --- a/src/infra/capabilities/containers/screen-share/index.tsx +++ b/src/infra/capabilities/containers/screen-share/index.tsx @@ -1,5 +1,5 @@ import { useStore } from '@classroom/infra/hooks/ui-store'; -import { EduStream } from 'agora-edu-core'; +import { EduClassroomConfig, EduRoomTypeEnum, EduStream } from 'agora-edu-core'; import { AGRenderMode } from 'agora-rte-sdk'; import classnames from 'classnames'; import { observer } from 'mobx-react'; @@ -9,25 +9,47 @@ import { useI18n } from 'agora-common-libs'; import './index.css'; import { ComponentLevelRules } from '../../config'; -const ScreenShareLocalTrackPlayer = observer(() => { +const LocalScreenShare = observer(() => { + const ref = useRef(null); + const { + streamUIStore: {setupLocalScreenShare }, + } = useStore(); + useEffect(() => { + if (ref.current) { + setupLocalScreenShare(ref.current) + } + }, [ref.current]); + return ( +
+
+ ) +}) + +const ScreenShareLocalTrackPlayer = observer(({stream}:{stream:EduStream}) => { const transI18n = useI18n(); const { - streamUIStore: { stopScreenShareCapture, localScreenShareOff }, + + streamUIStore: { stopScreenShareCapture, localScreenShareOff, setupLocalScreenShare }, } = useStore(); const [icon, setIcon] = useState(SvgIconEnum.SHARE_DEFAULT); + const isBigClass = EduClassroomConfig.shared.sessionInfo.roomType === EduRoomTypeEnum.RoomBigClass return localScreenShareOff ? null : ( -
- -
+ <> +
+ +
+ {isBigClass && stream && stream.isLocal ? : null} + ); }); @@ -72,7 +94,6 @@ export const ScreenShareContainer = observer>( ); const localcls = classnames('local-screen-share-container', className); - return screenShareStream ? ( {screenShareStream?.isLocal ? ( @@ -82,7 +103,7 @@ export const ScreenShareContainer = observer>( top: `calc(100% - ${boardAreaHeight}px)`, zIndex: ComponentLevelRules.ScreenShare, }}> - + ) : screenShareStream && !screenShareStream.isLocal ? (
diff --git a/src/infra/capabilities/containers/toolbar/tool-cabinet/index.tsx b/src/infra/capabilities/containers/toolbar/tool-cabinet/index.tsx index b9497c5af..490905287 100644 --- a/src/infra/capabilities/containers/toolbar/tool-cabinet/index.tsx +++ b/src/infra/capabilities/containers/toolbar/tool-cabinet/index.tsx @@ -38,12 +38,13 @@ export const ToolCabinetContainer = visibilityControl( name, }; }); - const handleClick = useCallback((cabinetId: string) => { setVisible(false); - isInstalled(cabinetId) - ? openExtensionCabinet(cabinetId, false) - : openBuiltinCabinet(cabinetId); + if(isInstalled(cabinetId)){ + openExtensionCabinet(cabinetId, false) + }else{ + openBuiltinCabinet(cabinetId); + } }, []); return ( diff --git a/src/infra/stores/common/group/index.ts b/src/infra/stores/common/group/index.ts index a2c7d5466..430c8bbb5 100644 --- a/src/infra/stores/common/group/index.ts +++ b/src/infra/stores/common/group/index.ts @@ -700,11 +700,11 @@ export class GroupUIStore extends EduUIStoreBase { await this.classroomStore.connectionStore.joinRTC(); - await this.classroomStore.connectionStore.checkIn( - EduClassroomConfig.shared.sessionInfo, - SceneType.Main, - 'check-in' - ); + // await this.classroomStore.connectionStore.checkIn( + // EduClassroomConfig.shared.sessionInfo, + // SceneType.Main, + // 'check-in' + // ); } catch (e) { this.shareUIStore.addGenericErrorDialog(e as AGError); } finally { diff --git a/src/infra/stores/common/index.ts b/src/infra/stores/common/index.ts index 9c63ce43b..9dbe013be 100644 --- a/src/infra/stores/common/index.ts +++ b/src/infra/stores/common/index.ts @@ -28,6 +28,7 @@ import { VideoGalleryUIStore } from './video-gallery'; import { transI18n } from 'agora-common-libs'; import { Getters } from './getters'; + export class EduClassroomUIStore { protected _classroomStore: EduClassroomStore; protected _boardUIStore: BoardUIStore; @@ -192,7 +193,9 @@ export class EduClassroomUIStore { async join() { const { joinClassroom, joinRTC } = this.classroomStore.connectionStore; try { - await joinClassroom(); + await joinClassroom({ + mode: "entry" + }); } catch (e) { if (AGError.isOf(e as AGError, AGServiceErrorCode.SERV_CANNOT_JOIN_ROOM)) { return this.classroomStore.connectionStore.leaveClassroom(LeaveReason.kickOut); diff --git a/src/infra/stores/common/stream/index.ts b/src/infra/stores/common/stream/index.ts index 663fa34c4..993455cb3 100644 --- a/src/infra/stores/common/stream/index.ts +++ b/src/infra/stores/common/stream/index.ts @@ -259,6 +259,7 @@ export class StreamUIStore extends EduUIStoreBase { @computed get screenShareStream(): EduStream | undefined { const streamUuid = this.classroomStore.roomStore.screenShareStreamUuid as string; const stream = this.classroomStore.streamStore.streamByStreamUuid.get(streamUuid); + return stream; } diff --git a/src/infra/stores/common/toolbar/index.ts b/src/infra/stores/common/toolbar/index.ts index 9cf72a41f..0037242b1 100644 --- a/src/infra/stores/common/toolbar/index.ts +++ b/src/infra/stores/common/toolbar/index.ts @@ -313,7 +313,7 @@ export class ToolbarUIStore extends EduUIStoreBase { } else { //not supported, start directly //web不需要传入屏幕id和类型,置为undefined,开启分享声音 - this.classroomStore.mediaStore.startScreenShareCapture({ withAudio: true }); + this.classroomStore.mediaStore.startScreenShareCapture({ localPreview: true, withAudio: true }); } } } @@ -366,6 +366,7 @@ export class ToolbarUIStore extends EduUIStoreBase { id: itemId, type: item.type, withAudio, + localPreview: true }); this.classroomStore.mediaStore.setCurrentScreenShareDevice(item); }, 0); @@ -375,14 +376,29 @@ export class ToolbarUIStore extends EduUIStoreBase { windowList: windows, }); } + /** * 打开内建工具 * @param id */ @action.bound async openBuiltinCabinet(id: string) { + switch (id) { case CabinetItemEnum.ScreenShare: + // 大班课才会出现屏幕共享冲突 + if(EduClassroomConfig.shared.sessionInfo.roomType === EduRoomTypeEnum.RoomBigClass){ + const streamUuid = this.classroomStore.roomStore.screenShareStreamUuid as string; + const stream = this.classroomStore.streamStore.streamByStreamUuid.get(streamUuid); + if (stream && stream.isLocal == false){ + // 有人共享,这个人不是自己 + this.shareUIStore.addToast( + transI18n('toast2.no_permission_to_share_screen'), + 'error', + ); + return; + } + } if (this.isScreenSharing) { this.classroomStore.mediaStore.stopScreenShareCapture(); return; @@ -609,6 +625,24 @@ export class ToolbarUIStore extends EduUIStoreBase { */ @computed get cabinetItems(): CabinetItem[] { + const { role, roomType } = EduClassroomConfig.shared.sessionInfo; + if(roomType == EduRoomTypeEnum.RoomBigClass){ + const { widgetController } = this.classroomStore.widgetStore; + const props = widgetController?.getWidgetUserProperties("easemobIM") || {}; + + const chatGroupUuids = props.chatGroupUuids || [] + + // 大班课,主助教工具栏只有屏幕共享 + if(role == EduRoleTypeEnum.assistant && chatGroupUuids.length == 0){ + return [ + { + id: CabinetItemEnum.ScreenShare, + iconType: 'share-screen', + name: transI18n('scaffold.screen_share'), + }, + ] + } + } const extapps = [ { id: CabinetItemEnum.ScreenShare, @@ -688,11 +722,32 @@ export class ToolbarUIStore extends EduUIStoreBase { * @returns */ @computed get tools(): ToolbarItem[] { - const { role } = EduClassroomConfig.shared.sessionInfo; - - return [EduRoleTypeEnum.teacher, EduRoleTypeEnum.assistant].includes(role) + const { role, roomType } = EduClassroomConfig.shared.sessionInfo; + + if(roomType == EduRoomTypeEnum.RoomBigClass){ + const { widgetController } = this.classroomStore.widgetStore; + const props = widgetController?.getWidgetUserProperties("easemobIM") || {}; + + const chatGroupUuids = props.chatGroupUuids || [] + + if(role == EduRoleTypeEnum.teacher){ + return this.teacherTools + }else if(role == EduRoleTypeEnum.assistant){ + if(chatGroupUuids.length > 0){ + // 子助教工具栏没有花名册 + return this.asisstantTools + }else{ + // 总助教与老师工具栏一致 + return this.mainAsisstantTools + } + }else{ + return this.studentTools; + } + }else{ + return [EduRoleTypeEnum.teacher, EduRoleTypeEnum.assistant].includes(role) ? this.teacherTools : this.studentTools; + } } /** @@ -822,6 +877,201 @@ export class ToolbarUIStore extends EduUIStoreBase { return _tools; } + /** + * 主助教老师工具栏工具列表 + * @returns + */ + @computed + get mainAsisstantTools(): ToolbarItem[] { + let _tools: ToolbarItem[] = []; + if (this.boardApi.mounted) { + _tools = [ + ToolbarItem.fromData({ + value: 'clicker', + label: 'scaffold.clicker', + icon: 'select', + category: ToolbarItemCategory.Clicker, + }), + ToolbarItem.fromData({ + // selector use clicker icon + value: 'selection', + label: 'scaffold.selector', + icon: 'clicker', + category: ToolbarItemCategory.Selector, + }), + ToolbarItem.fromData({ + value: 'pen', + label: 'scaffold.pencil', + icon: 'pen', + category: ToolbarItemCategory.PenPicker, + }), + ToolbarItem.fromData({ + value: 'text', + label: 'scaffold.text', + icon: 'text', + category: ToolbarItemCategory.Text, + }), + ToolbarItem.fromData({ + value: 'eraser', + label: 'scaffold.eraser', + icon: 'eraser', + category: ToolbarItemCategory.Eraser, + }), + + ToolbarItem.fromData({ + value: 'hand', + label: 'scaffold.move', + icon: 'hand', + category: ToolbarItemCategory.Hand, + }), + ToolbarItem.fromData({ + value: 'save', + label: 'scaffold.save', + icon: 'save-ghost', + category: ToolbarItemCategory.Save, + }), + + ToolbarItem.fromData({ + value: 'cloud', + label: 'scaffold.cloud_storage', + icon: 'cloud', + category: ToolbarItemCategory.CloudStorage, + }), + ToolbarItem.fromData({ + value: 'tools', + label: 'scaffold.tools', + icon: 'tools', + category: ToolbarItemCategory.Cabinet, + }), + ToolbarItem.fromData({ + value: 'register', + label: 'scaffold.register', + icon: 'register', + category: ToolbarItemCategory.Roster, + }), + ]; + + if (AgoraRteEngineConfig.platform === AgoraRteRuntimePlatform.Electron) { + _tools.splice( + 5, + 0, + ToolbarItem.fromData({ + value: 'slice', + label: 'scaffold.slice', + icon: 'slice', + category: ToolbarItemCategory.Slice, + }), + ); + } + } else { + _tools = [ + ToolbarItem.fromData({ + value: 'tools', + label: 'scaffold.tools', + icon: 'tools', + category: ToolbarItemCategory.Cabinet, + }), + ToolbarItem.fromData({ + value: 'register', + label: 'scaffold.register', + icon: 'register', + category: ToolbarItemCategory.Roster, + }), + ]; + } + + return _tools; + } + + + /** + * 子助教老师工具栏工具列表 + * @returns + */ + @computed + get asisstantTools(): ToolbarItem[] { + let _tools: ToolbarItem[] = []; + if (this.boardApi.mounted) { + _tools = [ + ToolbarItem.fromData({ + value: 'clicker', + label: 'scaffold.clicker', + icon: 'select', + category: ToolbarItemCategory.Clicker, + }), + ToolbarItem.fromData({ + // selector use clicker icon + value: 'selection', + label: 'scaffold.selector', + icon: 'clicker', + category: ToolbarItemCategory.Selector, + }), + ToolbarItem.fromData({ + value: 'pen', + label: 'scaffold.pencil', + icon: 'pen', + category: ToolbarItemCategory.PenPicker, + }), + ToolbarItem.fromData({ + value: 'text', + label: 'scaffold.text', + icon: 'text', + category: ToolbarItemCategory.Text, + }), + ToolbarItem.fromData({ + value: 'eraser', + label: 'scaffold.eraser', + icon: 'eraser', + category: ToolbarItemCategory.Eraser, + }), + + ToolbarItem.fromData({ + value: 'hand', + label: 'scaffold.move', + icon: 'hand', + category: ToolbarItemCategory.Hand, + }), + ToolbarItem.fromData({ + value: 'save', + label: 'scaffold.save', + icon: 'save-ghost', + category: ToolbarItemCategory.Save, + }), + + ToolbarItem.fromData({ + value: 'cloud', + label: 'scaffold.cloud_storage', + icon: 'cloud', + category: ToolbarItemCategory.CloudStorage, + }), + ]; + + if (AgoraRteEngineConfig.platform === AgoraRteRuntimePlatform.Electron) { + _tools.splice( + 5, + 0, + ToolbarItem.fromData({ + value: 'slice', + label: 'scaffold.slice', + icon: 'slice', + category: ToolbarItemCategory.Slice, + }), + ); + } + } else { + _tools = [ + ToolbarItem.fromData({ + value: 'register', + label: 'scaffold.register', + icon: 'register', + category: ToolbarItemCategory.Roster, + }), + ]; + } + + return _tools; + } + /** * 学生工具栏工具列表 * @returns diff --git a/src/infra/translate/zh.ts b/src/infra/translate/zh.ts index 51adcf005..db9e2c44e 100644 --- a/src/infra/translate/zh.ts +++ b/src/infra/translate/zh.ts @@ -453,6 +453,8 @@ export const zh = { save_error: '保存失败', saving: '正在导出,请稍候…', screen_shot_permission_denied: '使用屏幕截图前,请授权打开应用的访问权限', + no_permission_to_share_screen: '正在屏幕共享中,无法开启共享', + }, breakout_room: { create_prefix: '创建',