Skip to content

Commit

Permalink
feat(project): add replay room url protocol (#1955)
Browse files Browse the repository at this point in the history
* feat(project): add replay room url protocol

* refactor logic
  • Loading branch information
hyrious authored Jun 26, 2023
1 parent ec65a5d commit 4d628a4
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 17 deletions.
11 changes: 10 additions & 1 deletion desktop/main-app/src/bootup/init-url-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ export default async (): Promise<void> => {
});
}
},
replayRoom: (args, innerWindow) => {
if (args.has("roomUUID") && args.has("ownerUUID") && args.has("roomType")) {
innerWindow.window.webContents.send("request-replay-room", {
roomUUID: args.get("roomUUID"),
ownerUUID: args.get("ownerUUID"),
roomType: args.get("roomType"),
});
}
},
});

if (runtime.isMac) {
Expand Down Expand Up @@ -106,7 +115,7 @@ class URLProtocolHandler {
}
}

type ActionNames = "active" | "joinRoom";
type ActionNames = "active" | "joinRoom" | "replayRoom";
type ActionHandler = {
[key in ActionNames]: (arg: URLSearchParams, innerWindow: CustomWindow) => void;
};
Expand Down
17 changes: 17 additions & 0 deletions desktop/renderer-app/src/stores/url-protocol-store.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import type { RoomType } from "@netless/flat-server-api";
import { makeAutoObservable } from "mobx";

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

public constructor() {
this.toJoinRoomUUID = null;
this.toReplayRoom = null;
makeAutoObservable(this);
}

Expand All @@ -16,6 +19,20 @@ export class URLProtocolStore {
public clearToJoinRoomUUID(): void {
this.toJoinRoomUUID = null;
}

public updateToReplayRoom(roomUUID: string, ownerUUID: string, roomType: string): void {
if (this.isRoomType(roomType)) {
this.toReplayRoom = { roomUUID, ownerUUID, roomType };
}
}

private isRoomType(string: string): string is RoomType {
return string === "OneToOne" || string === "SmallClass" || string === "BigClass";
}

public clearToReplayRoom(): void {
this.toReplayRoom = null;
}
}

export const urlProtocolStore = new URLProtocolStore();
7 changes: 7 additions & 0 deletions desktop/renderer-app/src/tasks/init-url-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ const requestJoinRoom = (): void => {
});
};

const requestReplayRoom = (): void => {
ipcReceive("request-replay-room", ({ roomUUID, ownerUUID, roomType }) => {
urlProtocolStore.updateToReplayRoom(roomUUID, ownerUUID, roomType);
});
};

export const initURLProtocol = (): void => {
requestJoinRoom();
requestReplayRoom();
};
16 changes: 12 additions & 4 deletions desktop/renderer-app/src/utils/hooks/use-url-app-launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function useURLAppLauncher(): void {
};

useAutoRun(() => {
if (!urlProtocolStore.toJoinRoomUUID) {
if (!urlProtocolStore.toJoinRoomUUID && !urlProtocolStore.toReplayRoom) {
return;
}

Expand All @@ -47,10 +47,18 @@ export function useURLAppLauncher(): void {
return;
}

if (inClassRoom()?.roomUUID !== urlProtocolStore.toJoinRoomUUID) {
void joinRoomHandler(urlProtocolStore.toJoinRoomUUID, pushHistory);
if (urlProtocolStore.toJoinRoomUUID) {
if (inClassRoom()?.roomUUID !== urlProtocolStore.toJoinRoomUUID) {
void joinRoomHandler(urlProtocolStore.toJoinRoomUUID, pushHistory);
}
urlProtocolStore.clearToJoinRoomUUID();
return;
}

urlProtocolStore.clearToJoinRoomUUID();
if (urlProtocolStore.toReplayRoom) {
pushHistory(RouteNameType.ReplayPage, urlProtocolStore.toReplayRoom);
urlProtocolStore.clearToReplayRoom();
return;
}
});
}
3 changes: 2 additions & 1 deletion packages/flat-pages/src/AppRoutes/AppRouteContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ export const AppRouteContainer = observer<AppRouteContainerProps>(function AppRo
const hasHeader =
pageStore.name !== null && pageStore.name && routePages[pageStore.name].hasHeader;

if (isWeChatBrowser && !routeProps.location.pathname.startsWith("/join/")) {
const pathname = routeProps.location.pathname;
if (isWeChatBrowser && !pathname.startsWith("/join/") && !pathname.startsWith("/replay/")) {
return <WeChatRedirect />;
}

Expand Down
26 changes: 19 additions & 7 deletions packages/flat-pages/src/AppRoutes/WeChatRedirect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import "../JoinPage/style.less";
import logoSVG from "../JoinPage/icons/logo-sm.svg";
import openInBrowserSVG from "../JoinPage/icons/open-in-browser.svg";

import React, { useState } from "react";
import React, { useCallback, useEffect, useState } from "react";
import { useLanguage, useTranslate } from "@netless/flat-i18n";
import {
FLAT_DOWNLOAD_URL,
Expand All @@ -12,25 +12,37 @@ import {
SERVICE_URL,
SERVICE_URL_CN,
} from "../constants/process";
import { isWeChatBrowser } from "../utils/user-agent";

export interface WeChatRedirectProps {
url?: string;
open?: boolean;
}

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

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

const openApp = (): void => {
window.location.href = "x-agora-flat-client://active";
setOpenCount(openCount + 1);
};
const openApp = useCallback((): void => {
window.location.href = url || "x-agora-flat-client://active";
setOpenCount(count => count + 1);
}, [url]);

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

useEffect(() => {
if (open) {
openApp();
}
}, [open, openApp]);

return (
<div className="join-page-mobile-container">
<div className="join-page-mobile-effect"></div>
Expand All @@ -56,7 +68,7 @@ export const WeChatRedirect = (): React.ReactElement => {
{t("service-policy")}
</a>
</div>
{openCount > 0 && (
{openCount > 0 && isWeChatBrowser && (
<div className="join-page-mobile-wechat-overlay">
<img alt="[open-in-browser]" src={openInBrowserSVG} />
<strong>{t("open-in-browser")}</strong>
Expand Down
26 changes: 22 additions & 4 deletions packages/flat-pages/src/ReplayPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,47 @@ import "./ReplayPage.less";

import classNames from "classnames";
import { observer } from "mobx-react-lite";
import React, { useContext, useState } from "react";
import React, { useContext, useMemo, useState } from "react";
import { RouteComponentProps, useHistory } from "react-router-dom";
import { useWindowSize } from "react-use";

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

import ExitReplayConfirm from "../components/ExitReplayConfirm";
import { WeChatRedirect } from "../AppRoutes/WeChatRedirect";
import { ExitReplayConfirm } from "../components/ExitReplayConfirm";
import { WindowsSystemBtnContext } from "../components/StoreProvider";
import { useClassroomReplayStore } from "../utils/use-classroom-replay-store";
import { useLoginCheck } from "../utils/use-login-check";
import { ReplayList } from "./ReplayList";
import { ReplayVideo } from "./ReplayVideo";
import { ReplayWhiteboard } from "./ReplayWhiteboard";
import { withFlatServices } from "../components/FlatServicesContext";
import { isWeChatBrowser } from "../utils/user-agent";

export type ReplayPageProps = RouteComponentProps<{
roomUUID: string;
ownerUUID: string;
roomType: RoomType;
}>;

export const ReplayPage = withFlatServices("whiteboard")(
observer<ReplayPageProps>(function ReplayPage({ match }) {
export const ReplayPage = observer<ReplayPageProps>(function ReplayPage({ ...props }) {
const { width } = useWindowSize(1080);

const url = useMemo(() => {
const { roomUUID, ownerUUID, roomType } = props.match.params;
return `x-agora-flat-client://replayRoom?roomUUID=${roomUUID}&ownerUUID=${ownerUUID}&roomType=${roomType}`;
}, [props.match]);

if (isWeChatBrowser || width < 480) {
return <WeChatRedirect open url={url} />;
}

return <ReplayPageImpl {...props} />;
});

export const ReplayPageImpl = withFlatServices("whiteboard")(
observer<ReplayPageProps>(function ReplayPageImpl({ match }) {
useLoginCheck();

const history = useHistory();
Expand Down
5 changes: 5 additions & 0 deletions packages/flat-types/src/ipc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ export interface EmitEvents {
"request-join-room": {
roomUUID: string;
};
"request-replay-room": {
roomUUID: string;
ownerUUID: string;
roomType: string;
};
}

0 comments on commit 4d628a4

Please sign in to comment.