mirror of
https://github.com/vector-im/element-call.git
synced 2026-08-29 21:15:19 +00:00
This moves the media devices state out of React to further our transition to a MVVM architecture in which we can more easily model and store complex application state. I have created an AppViewModel to act as the overarching state holder for any future non-React state we end up creating, and the MediaDevices reside within this. We should move more application logic (including the CallViewModel itself) there in the future.
111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
/*
|
|
Copyright 2021-2024 New Vector Ltd.
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
import { type FC, type JSX, Suspense, useEffect, useState } from "react";
|
|
import { BrowserRouter, Route, useLocation, Routes } from "react-router-dom";
|
|
import * as Sentry from "@sentry/react";
|
|
import { TooltipProvider } from "@vector-im/compound-web";
|
|
import { logger } from "matrix-js-sdk/lib/logger";
|
|
|
|
import { HomePage } from "./home/HomePage";
|
|
import { LoginPage } from "./auth/LoginPage";
|
|
import { RegisterPage } from "./auth/RegisterPage";
|
|
import { RoomPage } from "./room/RoomPage";
|
|
import { ClientProvider } from "./ClientContext";
|
|
import { ErrorPage, LoadingPage } from "./FullScreenView";
|
|
import { DisconnectedBanner } from "./DisconnectedBanner";
|
|
import { Initializer } from "./initializer";
|
|
import { widget } from "./widget";
|
|
import { useTheme } from "./useTheme";
|
|
import { ProcessorProvider } from "./livekit/TrackProcessorContext";
|
|
import { type AppViewModel } from "./state/AppViewModel";
|
|
import { MediaDevicesContext } from "./MediaDevicesContext";
|
|
|
|
const SentryRoute = Sentry.withSentryReactRouterV7Routing(Route);
|
|
|
|
interface SimpleProviderProps {
|
|
children: JSX.Element;
|
|
}
|
|
|
|
const BackgroundProvider: FC<SimpleProviderProps> = ({ children }) => {
|
|
const { pathname } = useLocation();
|
|
|
|
useEffect(() => {
|
|
let backgroundImage = "";
|
|
if (!["/login", "/register"].includes(pathname) && !widget) {
|
|
backgroundImage = "var(--background-gradient)";
|
|
}
|
|
|
|
document.getElementsByTagName("body")[0].style.backgroundImage =
|
|
backgroundImage;
|
|
}, [pathname]);
|
|
|
|
return <>{children}</>;
|
|
};
|
|
const ThemeProvider: FC<SimpleProviderProps> = ({ children }) => {
|
|
useTheme();
|
|
return children;
|
|
};
|
|
|
|
interface Props {
|
|
vm: AppViewModel;
|
|
}
|
|
|
|
export const App: FC<Props> = ({ vm }) => {
|
|
const [loaded, setLoaded] = useState(false);
|
|
useEffect(() => {
|
|
Initializer.init()
|
|
?.then(async () => {
|
|
if (loaded) return;
|
|
setLoaded(true);
|
|
await widget?.api.sendContentLoaded();
|
|
})
|
|
.catch(logger.error);
|
|
});
|
|
|
|
return (
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore
|
|
<BrowserRouter>
|
|
<BackgroundProvider>
|
|
<ThemeProvider>
|
|
<TooltipProvider>
|
|
{loaded ? (
|
|
<Suspense fallback={null}>
|
|
<ClientProvider>
|
|
<MediaDevicesContext.Provider value={vm.mediaDevices}>
|
|
<ProcessorProvider>
|
|
<Sentry.ErrorBoundary
|
|
fallback={(error) => (
|
|
<ErrorPage error={error} widget={widget} />
|
|
)}
|
|
>
|
|
<DisconnectedBanner />
|
|
<Routes>
|
|
<SentryRoute path="/" element={<HomePage />} />
|
|
<SentryRoute path="/login" element={<LoginPage />} />
|
|
<SentryRoute
|
|
path="/register"
|
|
element={<RegisterPage />}
|
|
/>
|
|
<SentryRoute path="*" element={<RoomPage />} />
|
|
</Routes>
|
|
</Sentry.ErrorBoundary>
|
|
</ProcessorProvider>
|
|
</MediaDevicesContext.Provider>
|
|
</ClientProvider>
|
|
</Suspense>
|
|
) : (
|
|
<LoadingPage />
|
|
)}
|
|
</TooltipProvider>
|
|
</ThemeProvider>
|
|
</BackgroundProvider>
|
|
</BrowserRouter>
|
|
);
|
|
};
|