Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(flat-rtc): add share screen #1508

Merged
merged 5 commits into from
May 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion desktop/renderer-app/src/api-middleware/rtc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class Rtc {
throw new Error("Agora App Id not set.");
}

this.rtcEngine = window.rtcEngine;
this.rtcEngine = (window as any).agoraRtcSDK$.value;

this.rtcEngine.on("tokenPrivilegeWillExpire", this.renewToken);
this.rtcEngine.on("groupAudioVolumeIndication", this.updateVolumeLevel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,33 @@ import "./style.less";
import React, { useEffect, useMemo, useRef } from "react";
import { observer } from "mobx-react-lite";
import classNames from "classnames";
import type { ShareScreenStore } from "../../../stores/share-screen-store";

import { ClassRoomStore } from "../../../stores/class-room-store";
import { ShareScreenTip } from "../ShareScreenTip";

interface ShareScreenProps {
shareScreenStore: ShareScreenStore;
classRoomStore: ClassRoomStore;
}

export const ShareScreen = observer<ShareScreenProps>(function ShareScreen({ shareScreenStore }) {
export const ShareScreen = observer<ShareScreenProps>(function ShareScreen({ classRoomStore }) {
const ref = useRef<HTMLDivElement>(null);

useEffect(() => {
if (ref.current) {
shareScreenStore.updateElement(ref.current);
classRoomStore.rtc.shareScreen.setElement(ref.current);
}
}, [shareScreenStore]);
}, [classRoomStore]);

const classNameList = useMemo(() => {
return classNames("share-screen", {
active: shareScreenStore.existOtherShareScreen,
active: classRoomStore.isRemoteScreenSharing,
});
}, [shareScreenStore.existOtherShareScreen]);
}, [classRoomStore.isRemoteScreenSharing]);

return (
<>
<div ref={ref} className={classNameList} />
{shareScreenStore.enableShareScreenStatus && (
<ShareScreenTip shareScreenStore={shareScreenStore} />
)}
{classRoomStore.isScreenSharing && <ShareScreenTip classRoomStore={classRoomStore} />}
</>
);
});
Original file line number Diff line number Diff line change
@@ -1,48 +1,50 @@
import "./style.less";

import classNames from "classnames";
import React, { useCallback, useEffect, useState } from "react";
import { observer } from "mobx-react-lite";
import { ScreenInfo, ShareSymbol } from "../../../../api-middleware/share-screen";
import { getScreenInfo, uint8ArrayToImageURL } from "./Utils";
import classNames from "classnames";
import { ShareScreenStore } from "../../../../stores/share-screen-store";
import { message } from "antd";
import { useTranslation } from "react-i18next";
import { FlatRTCShareScreenInfo } from "@netless/flat-rtc";

import { uint8ArrayToImageURL } from "./Utils";
import { ClassRoomStore } from "../../../../stores/class-room-store";

interface ScreenListProps {
screenInfo: ScreenInfo;
shareScreenStore: ShareScreenStore;
screenInfo: FlatRTCShareScreenInfo[];
classRoomStore: ClassRoomStore;
}

export const ScreenList = observer<ScreenListProps>(function ShareScreen({
screenInfo,
shareScreenStore,
classRoomStore,
}) {
const [activeInfo, setActiveInfo] = useState("");
const { t } = useTranslation();

useEffect(() => {
if (screenInfo.windowList.length === 0) {
if (screenInfo.length === 0) {
void message.error(t("share-screen.desktop-not-permission"));
}
}, [screenInfo.windowList, t]);
}, [screenInfo, t]);

const onClick = useCallback(
(screenInfo: ShareSymbol, activeKey: string) => {
(screenInfo: FlatRTCShareScreenInfo, activeKey: string) => {
setActiveInfo(activeKey);
shareScreenStore.updateShareSymbolInfo(screenInfo);
classRoomStore.updateSelectedScreenInfo(screenInfo);
},
[shareScreenStore],
[classRoomStore],
);

const cancelSelected = useCallback(() => {
setActiveInfo("");
shareScreenStore.updateShareSymbolInfo(null);
}, [shareScreenStore]);
classRoomStore.updateSelectedScreenInfo(null);
}, [classRoomStore]);

return (
<div className="screen-list">
{screenInfo.displayList.map((info, index) => {
const key = `display-${index}`;
{screenInfo.map(info => {
const key = `${info.type}-${info.screenId}`;
const isActive = activeInfo === key;

return (
Expand All @@ -55,27 +57,13 @@ export const ScreenList = observer<ScreenListProps>(function ShareScreen({
/>
);
})}
{screenInfo.windowList.map(info => {
const key = `window-${info.windowId}`;
const isActive = activeInfo === key;

return (
<ScreenItem
key={key}
active={activeInfo === key}
activeKey={key}
handleClick={isActive ? cancelSelected : onClick}
info={info}
/>
);
})}
</div>
);
});

interface ScreenItemProps {
info: ScreenInfo["windowList"][0] | ScreenInfo["displayList"][0];
handleClick: (screenInfo: ShareSymbol, key: string) => void;
info: FlatRTCShareScreenInfo;
handleClick: (screenInfo: FlatRTCShareScreenInfo, key: string) => void;
active: boolean;
activeKey: string;
}
Expand All @@ -86,20 +74,18 @@ const ScreenItem = observer<ScreenItemProps>(function ScreenItem({
active,
activeKey,
}) {
const screenInfo = getScreenInfo(info);

return (
<>
<div className="screen-item">
<div
className={classNames("screen-image-box", {
active,
})}
onClick={() => handleClick(screenInfo, activeKey)}
onClick={() => handleClick(info, activeKey)}
>
<img alt="screenshots" src={uint8ArrayToImageURL(info.image)} />
</div>
<span>{screenInfo.name}</span>
<span>{info.name}</span>
</div>
</>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
import "./style.less";
import React, { useCallback, useEffect, useLayoutEffect, useState } from "react";
import { observer } from "mobx-react-lite";

import { Button, Modal, Spin } from "antd";
import { ShareScreenStore } from "../../../stores/share-screen-store";
import { ScreenList } from "./ScreenList";
import classNames from "classnames";
import { observer } from "mobx-react-lite";
import React, { useCallback, useLayoutEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { ClassRoomStore } from "../../../stores/class-room-store";
import { ScreenList } from "./ScreenList";

interface ShareScreenPickerProps {
shareScreenStore: ShareScreenStore;
classRoomStore: ClassRoomStore;
handleOk: () => void;
}

const ShareScreenPickerModel = observer<ShareScreenPickerProps>(function ShareScreen({
shareScreenStore,
classRoomStore,
handleOk,
}) {
const { t } = useTranslation();

useLayoutEffect(() => {
shareScreenStore.resetScreenInfo();
}, [shareScreenStore]);

useEffect(() => {
shareScreenStore.updateScreenInfo();
}, [shareScreenStore]);
classRoomStore.refreshShareScreenInfo();
}, [classRoomStore]);

const closeModal = useCallback(() => {
shareScreenStore.updateShowShareScreenPicker(false);
}, [shareScreenStore]);
classRoomStore.updateShowShareScreenPicker(false);
}, [classRoomStore]);

const isSelected = shareScreenStore.shareSymbol !== null;
const isSelected = classRoomStore.selectedScreenInfo !== null;

return (
<div>
Expand All @@ -53,13 +51,13 @@ const ShareScreenPickerModel = observer<ShareScreenPickerProps>(function ShareSc
>
<div
className={classNames("share-screen-picker", {
loading: shareScreenStore.screenInfo === null,
loading: classRoomStore.shareScreenInfo.length === 0,
})}
>
{shareScreenStore.screenInfo ? (
{classRoomStore.shareScreenInfo.length > 0 ? (
<ScreenList
screenInfo={shareScreenStore.screenInfo}
shareScreenStore={shareScreenStore}
classRoomStore={classRoomStore}
screenInfo={classRoomStore.shareScreenInfo}
/>
) : (
<Spin size="large" />
Expand All @@ -71,11 +69,11 @@ const ShareScreenPickerModel = observer<ShareScreenPickerProps>(function ShareSc
});

export const ShareScreenPicker = observer<ShareScreenPickerProps>(function ShareScreen({
shareScreenStore,
classRoomStore,
handleOk,
}) {
return shareScreenStore.showShareScreenPicker ? (
<ShareScreenPickerModel handleOk={handleOk} shareScreenStore={shareScreenStore} />
return classRoomStore.showShareScreenPicker ? (
<ShareScreenPickerModel classRoomStore={classRoomStore} handleOk={handleOk} />
) : null;
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import React from "react";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import ReactDOM from "react-dom";
import "./style.less";
import { portalWindowManager } from "../../../utils/portal-window-manager";
import { ipcAsyncByShareScreenTipWindow } from "../../../utils/ipc";
import dragSVG from "../../../assets/image/drag.svg";
import { Button } from "antd";
import { ShareScreenStore } from "../../../stores/share-screen-store";

import React, { useCallback, useEffect, useState } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react-lite";
import { useTranslation } from "react-i18next";
import { Button } from "antd";

import { ClassRoomStore } from "../../../stores/class-room-store";
import { useSafePromise } from "../../../utils/hooks/lifecycle";
import { ipcAsyncByShareScreenTipWindow } from "../../../utils/ipc";
import { portalWindowManager } from "../../../utils/portal-window-manager";

interface ShareScreenTipProps {
shareScreenStore: ShareScreenStore;
classRoomStore: ClassRoomStore;
}

export const ShareScreenTip = observer<ShareScreenTipProps>(function ShareScreenTip({
shareScreenStore,
classRoomStore,
}) {
const sp = useSafePromise();
const { t } = useTranslation();
Expand All @@ -35,9 +36,10 @@ export const ShareScreenTip = observer<ShareScreenTipProps>(function ShareScreen
};
}, [containerEl, sp, t]);

const stopShareScreen = (): void => {
shareScreenStore.close().catch(console.error);
};
const stopShareScreen = useCallback(
() => classRoomStore.toggleShareScreen(false),
[classRoomStore],
);

return ReactDOM.createPortal(
<div className={"share-screen-tip"}>
Expand Down
19 changes: 8 additions & 11 deletions desktop/renderer-app/src/pages/BigClassPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ export const BigClassPage = observer<BigClassPageProps>(function BigClassPage()
i18n,
});
const whiteboardStore = classRoomStore.whiteboardStore;
const shareScreenStore = classRoomStore.shareScreenStore;

const { confirm, ...exitConfirmModalProps } = useExitRoomConfirmModal(classRoomStore);

Expand Down Expand Up @@ -198,10 +197,10 @@ export const BigClassPage = observer<BigClassPageProps>(function BigClassPage()
}

function handleShareScreen(): void {
if (shareScreenStore.enableShareScreenStatus) {
shareScreenStore.close().catch(console.error);
if (classRoomStore.isScreenSharing) {
classRoomStore.toggleShareScreen(false);
} else {
shareScreenStore.updateShowShareScreenPicker(true);
classRoomStore.updateShowShareScreenPicker(true);
}
}

Expand All @@ -223,12 +222,12 @@ export const BigClassPage = observer<BigClassPageProps>(function BigClassPage()
/>
<div className="big-class-realtime-content">
<div className="big-class-realtime-content-container">
<ShareScreen shareScreenStore={shareScreenStore} />
<ShareScreen classRoomStore={classRoomStore} />
<ShareScreenPicker
classRoomStore={classRoomStore}
handleOk={() => {
shareScreenStore.enable();
classRoomStore.toggleShareScreen(true);
}}
shareScreenStore={shareScreenStore}
/>
<Whiteboard
classRoomStore={classRoomStore}
Expand Down Expand Up @@ -275,11 +274,9 @@ export const BigClassPage = observer<BigClassPageProps>(function BigClassPage()
function renderTopBarRight(): React.ReactNode {
return (
<>
{whiteboardStore.isWritable && !shareScreenStore.existOtherShareScreen && (
{whiteboardStore.isWritable && !classRoomStore.isRemoteScreenSharing && (
<TopBarRightBtn
icon={
<SVGScreenSharing active={shareScreenStore.enableShareScreenStatus} />
}
icon={<SVGScreenSharing active={classRoomStore.isScreenSharing} />}
title={t("share-screen.self")}
onClick={handleShareScreen}
/>
Expand Down
Loading