Skip to content

Commit 4d628a4

Browse files
authored
feat(project): add replay room url protocol (netless-io#1955)
* feat(project): add replay room url protocol * refactor logic
1 parent ec65a5d commit 4d628a4

File tree

8 files changed

+94
-17
lines changed

8 files changed

+94
-17
lines changed

desktop/main-app/src/bootup/init-url-protocol.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ export default async (): Promise<void> => {
1717
});
1818
}
1919
},
20+
replayRoom: (args, innerWindow) => {
21+
if (args.has("roomUUID") && args.has("ownerUUID") && args.has("roomType")) {
22+
innerWindow.window.webContents.send("request-replay-room", {
23+
roomUUID: args.get("roomUUID"),
24+
ownerUUID: args.get("ownerUUID"),
25+
roomType: args.get("roomType"),
26+
});
27+
}
28+
},
2029
});
2130

2231
if (runtime.isMac) {
@@ -106,7 +115,7 @@ class URLProtocolHandler {
106115
}
107116
}
108117

109-
type ActionNames = "active" | "joinRoom";
118+
type ActionNames = "active" | "joinRoom" | "replayRoom";
110119
type ActionHandler = {
111120
[key in ActionNames]: (arg: URLSearchParams, innerWindow: CustomWindow) => void;
112121
};

desktop/renderer-app/src/stores/url-protocol-store.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
import type { RoomType } from "@netless/flat-server-api";
12
import { makeAutoObservable } from "mobx";
23

34
export class URLProtocolStore {
45
// Receive the roomUUID parameters from ipc that for join room.
56
public toJoinRoomUUID: string | null;
7+
public toReplayRoom: { roomUUID: string; ownerUUID: string; roomType: RoomType } | null;
68

79
public constructor() {
810
this.toJoinRoomUUID = null;
11+
this.toReplayRoom = null;
912
makeAutoObservable(this);
1013
}
1114

@@ -16,6 +19,20 @@ export class URLProtocolStore {
1619
public clearToJoinRoomUUID(): void {
1720
this.toJoinRoomUUID = null;
1821
}
22+
23+
public updateToReplayRoom(roomUUID: string, ownerUUID: string, roomType: string): void {
24+
if (this.isRoomType(roomType)) {
25+
this.toReplayRoom = { roomUUID, ownerUUID, roomType };
26+
}
27+
}
28+
29+
private isRoomType(string: string): string is RoomType {
30+
return string === "OneToOne" || string === "SmallClass" || string === "BigClass";
31+
}
32+
33+
public clearToReplayRoom(): void {
34+
this.toReplayRoom = null;
35+
}
1936
}
2037

2138
export const urlProtocolStore = new URLProtocolStore();

desktop/renderer-app/src/tasks/init-url-protocol.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ const requestJoinRoom = (): void => {
1212
});
1313
};
1414

15+
const requestReplayRoom = (): void => {
16+
ipcReceive("request-replay-room", ({ roomUUID, ownerUUID, roomType }) => {
17+
urlProtocolStore.updateToReplayRoom(roomUUID, ownerUUID, roomType);
18+
});
19+
};
20+
1521
export const initURLProtocol = (): void => {
1622
requestJoinRoom();
23+
requestReplayRoom();
1724
};

desktop/renderer-app/src/utils/hooks/use-url-app-launcher.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function useURLAppLauncher(): void {
3838
};
3939

4040
useAutoRun(() => {
41-
if (!urlProtocolStore.toJoinRoomUUID) {
41+
if (!urlProtocolStore.toJoinRoomUUID && !urlProtocolStore.toReplayRoom) {
4242
return;
4343
}
4444

@@ -47,10 +47,18 @@ export function useURLAppLauncher(): void {
4747
return;
4848
}
4949

50-
if (inClassRoom()?.roomUUID !== urlProtocolStore.toJoinRoomUUID) {
51-
void joinRoomHandler(urlProtocolStore.toJoinRoomUUID, pushHistory);
50+
if (urlProtocolStore.toJoinRoomUUID) {
51+
if (inClassRoom()?.roomUUID !== urlProtocolStore.toJoinRoomUUID) {
52+
void joinRoomHandler(urlProtocolStore.toJoinRoomUUID, pushHistory);
53+
}
54+
urlProtocolStore.clearToJoinRoomUUID();
55+
return;
5256
}
5357

54-
urlProtocolStore.clearToJoinRoomUUID();
58+
if (urlProtocolStore.toReplayRoom) {
59+
pushHistory(RouteNameType.ReplayPage, urlProtocolStore.toReplayRoom);
60+
urlProtocolStore.clearToReplayRoom();
61+
return;
62+
}
5563
});
5664
}

packages/flat-pages/src/AppRoutes/AppRouteContainer.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export const AppRouteContainer = observer<AppRouteContainerProps>(function AppRo
6464
const hasHeader =
6565
pageStore.name !== null && pageStore.name && routePages[pageStore.name].hasHeader;
6666

67-
if (isWeChatBrowser && !routeProps.location.pathname.startsWith("/join/")) {
67+
const pathname = routeProps.location.pathname;
68+
if (isWeChatBrowser && !pathname.startsWith("/join/") && !pathname.startsWith("/replay/")) {
6869
return <WeChatRedirect />;
6970
}
7071

packages/flat-pages/src/AppRoutes/WeChatRedirect.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import "../JoinPage/style.less";
33
import logoSVG from "../JoinPage/icons/logo-sm.svg";
44
import openInBrowserSVG from "../JoinPage/icons/open-in-browser.svg";
55

6-
import React, { useState } from "react";
6+
import React, { useCallback, useEffect, useState } from "react";
77
import { useLanguage, useTranslate } from "@netless/flat-i18n";
88
import {
99
FLAT_DOWNLOAD_URL,
@@ -12,25 +12,37 @@ import {
1212
SERVICE_URL,
1313
SERVICE_URL_CN,
1414
} from "../constants/process";
15+
import { isWeChatBrowser } from "../utils/user-agent";
16+
17+
export interface WeChatRedirectProps {
18+
url?: string;
19+
open?: boolean;
20+
}
1521

1622
// This is a simplified version of JoinPageMobile.tsx, it can not join room.
17-
export const WeChatRedirect = (): React.ReactElement => {
23+
export const WeChatRedirect = ({ url, open }: WeChatRedirectProps): React.ReactElement => {
1824
const t = useTranslate();
1925
const language = useLanguage();
2026
const [openCount, setOpenCount] = useState(0);
2127

2228
const privacyURL = language.startsWith("zh") ? PRIVACY_URL_CN : PRIVACY_URL;
2329
const serviceURL = language.startsWith("zh") ? SERVICE_URL_CN : SERVICE_URL;
2430

25-
const openApp = (): void => {
26-
window.location.href = "x-agora-flat-client://active";
27-
setOpenCount(openCount + 1);
28-
};
31+
const openApp = useCallback((): void => {
32+
window.location.href = url || "x-agora-flat-client://active";
33+
setOpenCount(count => count + 1);
34+
}, [url]);
2935

3036
const download = (): void => {
3137
window.location.href = FLAT_DOWNLOAD_URL;
3238
};
3339

40+
useEffect(() => {
41+
if (open) {
42+
openApp();
43+
}
44+
}, [open, openApp]);
45+
3446
return (
3547
<div className="join-page-mobile-container">
3648
<div className="join-page-mobile-effect"></div>
@@ -56,7 +68,7 @@ export const WeChatRedirect = (): React.ReactElement => {
5668
{t("service-policy")}
5769
</a>
5870
</div>
59-
{openCount > 0 && (
71+
{openCount > 0 && isWeChatBrowser && (
6072
<div className="join-page-mobile-wechat-overlay">
6173
<img alt="[open-in-browser]" src={openInBrowserSVG} />
6274
<strong>{t("open-in-browser")}</strong>

packages/flat-pages/src/ReplayPage/index.tsx

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,47 @@ import "./ReplayPage.less";
22

33
import classNames from "classnames";
44
import { observer } from "mobx-react-lite";
5-
import React, { useContext, useState } from "react";
5+
import React, { useContext, useMemo, useState } from "react";
66
import { RouteComponentProps, useHistory } from "react-router-dom";
7+
import { useWindowSize } from "react-use";
78

89
import { RoomType } from "@netless/flat-server-api";
910
import { LoadingPage, TopBar } from "flat-components";
1011

11-
import ExitReplayConfirm from "../components/ExitReplayConfirm";
12+
import { WeChatRedirect } from "../AppRoutes/WeChatRedirect";
13+
import { ExitReplayConfirm } from "../components/ExitReplayConfirm";
1214
import { WindowsSystemBtnContext } from "../components/StoreProvider";
1315
import { useClassroomReplayStore } from "../utils/use-classroom-replay-store";
1416
import { useLoginCheck } from "../utils/use-login-check";
1517
import { ReplayList } from "./ReplayList";
1618
import { ReplayVideo } from "./ReplayVideo";
1719
import { ReplayWhiteboard } from "./ReplayWhiteboard";
1820
import { withFlatServices } from "../components/FlatServicesContext";
21+
import { isWeChatBrowser } from "../utils/user-agent";
1922

2023
export type ReplayPageProps = RouteComponentProps<{
2124
roomUUID: string;
2225
ownerUUID: string;
2326
roomType: RoomType;
2427
}>;
2528

26-
export const ReplayPage = withFlatServices("whiteboard")(
27-
observer<ReplayPageProps>(function ReplayPage({ match }) {
29+
export const ReplayPage = observer<ReplayPageProps>(function ReplayPage({ ...props }) {
30+
const { width } = useWindowSize(1080);
31+
32+
const url = useMemo(() => {
33+
const { roomUUID, ownerUUID, roomType } = props.match.params;
34+
return `x-agora-flat-client://replayRoom?roomUUID=${roomUUID}&ownerUUID=${ownerUUID}&roomType=${roomType}`;
35+
}, [props.match]);
36+
37+
if (isWeChatBrowser || width < 480) {
38+
return <WeChatRedirect open url={url} />;
39+
}
40+
41+
return <ReplayPageImpl {...props} />;
42+
});
43+
44+
export const ReplayPageImpl = withFlatServices("whiteboard")(
45+
observer<ReplayPageProps>(function ReplayPageImpl({ match }) {
2846
useLoginCheck();
2947

3048
const history = useHistory();

packages/flat-types/src/ipc/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,9 @@ export interface EmitEvents {
5656
"request-join-room": {
5757
roomUUID: string;
5858
};
59+
"request-replay-room": {
60+
roomUUID: string;
61+
ownerUUID: string;
62+
roomType: string;
63+
};
5964
}

0 commit comments

Comments
 (0)