diff --git a/apps/desktop-frontend/src/app/LeftMenuSidebar.tsx b/apps/desktop-frontend/src/app/LeftMenuSidebar.tsx
index 3dea40f8..3b9f044d 100644
--- a/apps/desktop-frontend/src/app/LeftMenuSidebar.tsx
+++ b/apps/desktop-frontend/src/app/LeftMenuSidebar.tsx
@@ -51,10 +51,6 @@ export function LeftMenuSidebar() {
// These are not centered
onClick={handleLinkClick("/analyzer")}
color={buttonColor("/analyzer")}
- // sx={{
- // display: "flex",
- // justifyContent: "center",
- // }}
>
diff --git a/apps/desktop-frontend/src/app/RootSaga.ts b/apps/desktop-frontend/src/app/RootSaga.ts
index f479724f..38ac2b27 100644
--- a/apps/desktop-frontend/src/app/RootSaga.ts
+++ b/apps/desktop-frontend/src/app/RootSaga.ts
@@ -3,6 +3,7 @@ import { API_BASE_URL } from "./backend/constants";
import { BackendState, stateChanged } from "./backend/slice";
import { SagaIterator } from "redux-saga";
import { push } from "connected-react-router";
+import { RewindTheater } from "@rewind/web-player/rewind";
function* waitForBackendState(state: BackendState): SagaIterator {
while (true) {
@@ -13,10 +14,12 @@ function* waitForBackendState(state: BackendState): SagaIterator {
}
}
-function* watchForBackendReady(): SagaIterator {
+function* watchForBackendReady(theater: RewindTheater): SagaIterator {
+ const { common, analyzer } = theater;
yield call(waitForBackendState, "READY");
- // yield spawn(watchReplaysAdded, REWIND_WS_URL);
yield put(push("/home")); // Theater
+ yield call(common.initialize.bind(common));
+ yield call(analyzer.initialize.bind(analyzer));
}
function* watchForBackendMissingSetup(): SagaIterator {
@@ -52,10 +55,10 @@ function* busyPollBackendState(): SagaIterator {
}
}
-export function createRewindRootSaga() {
+export function createRewindRootSaga({ theater }: { theater: RewindTheater }) {
return function* () {
yield spawn(watchForBackendMissingSetup);
- yield spawn(watchForBackendReady);
+ yield spawn(watchForBackendReady, theater);
yield spawn(busyPollBackendState);
};
}
diff --git a/apps/desktop-frontend/src/app/store.tsx b/apps/desktop-frontend/src/app/store.tsx
index 766215e0..1c86199a 100644
--- a/apps/desktop-frontend/src/app/store.tsx
+++ b/apps/desktop-frontend/src/app/store.tsx
@@ -8,6 +8,7 @@ import { createHashHistory } from "history";
import { connectRouter, routerMiddleware } from "connected-react-router";
import { rewindDesktopApi } from "./backend/api";
import { setupListeners } from "@reduxjs/toolkit/query";
+import { theater } from "./theater";
export const history = createHashHistory({});
@@ -35,7 +36,7 @@ const store = configureStore({
setupListeners(store.dispatch);
-sagaMiddleware.run(createRewindRootSaga());
+sagaMiddleware.run(createRewindRootSaga({ theater }));
export type RootState = ReturnType;
export type AppDispatch = typeof store.dispatch;
diff --git a/apps/desktop-frontend/src/app/theater.ts b/apps/desktop-frontend/src/app/theater.ts
new file mode 100644
index 00000000..d04f4808
--- /dev/null
+++ b/apps/desktop-frontend/src/app/theater.ts
@@ -0,0 +1,4 @@
+import { createRewindTheater } from "@rewind/web-player/rewind";
+
+const apiUrl = "http://localhost:7271";
+export const theater = createRewindTheater({ apiUrl });
diff --git a/apps/desktop-frontend/src/main.tsx b/apps/desktop-frontend/src/main.tsx
index 90c97b51..bcfbed3c 100644
--- a/apps/desktop-frontend/src/main.tsx
+++ b/apps/desktop-frontend/src/main.tsx
@@ -9,6 +9,7 @@ import { RewindTheme, TheaterProvider } from "@rewind/feature-replay-viewer";
import { RewindApp } from "./app/RewindApp";
import { FrontendPreloadAPI } from "@rewind/electron/api";
import { CssBaseline, ThemeProvider } from "@mui/material";
+import { theater } from "./app/theater";
declare global {
interface Window {
@@ -22,8 +23,7 @@ ReactDOM.render(
- {/*todo: just create theater outside and pass it in lol*/}
-
+
diff --git a/apps/web/src/app/webTestApp.tsx b/apps/web/src/app/webTestApp.tsx
index 30d906d8..654ac6c3 100644
--- a/apps/web/src/app/webTestApp.tsx
+++ b/apps/web/src/app/webTestApp.tsx
@@ -1,5 +1,5 @@
import { Box } from "@mui/material";
-import { Analyzer, useAnalysisApp, useTheater } from "@rewind/feature-replay-viewer";
+import { Analyzer, useAnalysisApp, useCommonManagers } from "@rewind/feature-replay-viewer";
import { useEffect } from "react";
import { SkinId } from "@rewind/web-player/rewind";
@@ -16,7 +16,7 @@ const chosenReplayId = centipede;
const skin: SkinId = { source: "osu", name: "- # re;owoTuna v1.1 『Selyu』 # -" };
export function WebTestApp() {
- const theater = useTheater();
+ const theater = useCommonManagers();
const analyzer = useAnalysisApp();
useEffect(() => {
// theater.changeSkin(skin);
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
index 17aabb3c..2ca1738c 100644
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -4,13 +4,18 @@ import * as ReactDOM from "react-dom";
import { WebTestApp } from "./app/webTestApp";
import { environment } from "./environments/environment";
import { CssBaseline, ThemeProvider } from "@mui/material";
+import { createRewindTheater } from "@rewind/web-player/rewind";
-// TODO: process.env.URL
-const url = environment.url;
+// This project assumes that the backend is already initialized
+
+const apiUrl = environment.url;
+export const theater = createRewindTheater({ apiUrl });
+theater.common.initialize();
+theater.analyzer.initialize();
ReactDOM.render(
-
+
diff --git a/libs/feature-replay-viewer/src/components/PlayBar.tsx b/libs/feature-replay-viewer/src/components/PlayBar.tsx
index 41d24dfd..fd5158cd 100644
--- a/libs/feature-replay-viewer/src/components/PlayBar.tsx
+++ b/libs/feature-replay-viewer/src/components/PlayBar.tsx
@@ -256,7 +256,7 @@ function GameTimeSlider() {
return (
= {
};
function BeatmapBackgroundSettings() {
- const theater = useTheater();
+ const theater = useCommonManagers();
const { beatmapBackgroundSettingsStore } = theater;
const settings = useObservable(() => beatmapBackgroundSettingsStore.settings$, { blur: 0, enabled: false, dim: 0 });
return (
@@ -55,7 +55,7 @@ function BeatmapBackgroundSettings() {
}
function BeatmapRenderSettings() {
- const { beatmapRenderSettingsStore } = useTheater();
+ const { beatmapRenderSettingsStore } = useCommonManagers();
const settings = useObservable(() => beatmapRenderSettingsStore.settings$, DEFAULT_BEATMAP_RENDER_SETTINGS);
return (
@@ -77,7 +77,7 @@ function BeatmapRenderSettings() {
}
function AnalysisCursorSettingsPanel() {
- const { analysisCursorSettingsStore } = useTheater();
+ const { analysisCursorSettingsStore } = useCommonManagers();
const settings = useObservable(() => analysisCursorSettingsStore.settings$, DEFAULT_ANALYSIS_CURSOR_SETTINGS);
return (
@@ -98,7 +98,7 @@ function AnalysisCursorSettingsPanel() {
}
function ReplayCursorSettingsPanel() {
- const { replayCursorSettingsStore } = useTheater();
+ const { replayCursorSettingsStore } = useCommonManagers();
const settings = useObservable(() => replayCursorSettingsStore.settings$, DEFAULT_REPLAY_CURSOR_SETTINGS);
return (
@@ -140,7 +140,7 @@ function GeneralSettings() {
function SkinsSettings() {
// TODO: Button for synchronizing skin list again
- const theater = useTheater();
+ const theater = useCommonManagers();
const { preferredSkinId } = useObservable(() => theater.skinSettingsStore.settings$, DEFAULT_SKIN_SETTINGS);
const chosenSkinId = stringToSkinId(preferredSkinId);
diff --git a/libs/feature-replay-viewer/src/hooks/audio.ts b/libs/feature-replay-viewer/src/hooks/audio.ts
index edf2c9e0..c84e05e2 100644
--- a/libs/feature-replay-viewer/src/hooks/audio.ts
+++ b/libs/feature-replay-viewer/src/hooks/audio.ts
@@ -1,9 +1,9 @@
-import { useTheater } from "../providers/TheaterProvider";
+import { useCommonManagers } from "../providers/TheaterProvider";
import { useObservable } from "rxjs-hooks";
import { AudioSettings } from "@rewind/web-player/rewind";
export function useAudioSettingsService() {
- const theater = useTheater();
+ const theater = useCommonManagers();
return theater.audioSettingsService;
}
diff --git a/libs/feature-replay-viewer/src/providers/TheaterProvider.tsx b/libs/feature-replay-viewer/src/providers/TheaterProvider.tsx
index df6e384f..a22705b1 100644
--- a/libs/feature-replay-viewer/src/providers/TheaterProvider.tsx
+++ b/libs/feature-replay-viewer/src/providers/TheaterProvider.tsx
@@ -1,23 +1,16 @@
-import React, { createContext, useContext, useEffect, useState } from "react";
-import { createRewindTheater } from "@rewind/web-player/rewind";
-
-type ITheaterContext = ReturnType;
+import React, { createContext, useContext } from "react";
+import { RewindTheater } from "@rewind/web-player/rewind";
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
-export const TheaterContext = createContext(null!);
+export const TheaterContext = createContext(null!);
interface TheaterProviderProps {
- apiUrl: string;
+ theater: RewindTheater;
children: React.ReactNode;
}
-export function TheaterProvider({ apiUrl, children }: TheaterProviderProps) {
- const [rewind] = useState(() => createRewindTheater({ apiUrl }));
- useEffect(() => {
- rewind.theater.initialize().then(() => console.log("Theater initialized"));
- rewind.analyzer.initialize();
- }, [rewind]);
- return {children};
+export function TheaterProvider({ theater, children }: TheaterProviderProps) {
+ return {children};
}
export function useTheaterContext() {
@@ -28,12 +21,12 @@ export function useTheaterContext() {
return context;
}
-export function useTheater() {
- const { theater } = useTheaterContext();
- return theater;
+export function useCommonManagers() {
+ const theater = useTheaterContext();
+ return theater.common;
}
export function useAnalysisApp() {
- const { analyzer } = useTheaterContext();
- return analyzer;
+ const theater = useTheaterContext();
+ return theater.analyzer;
}
diff --git a/libs/web-player/rewind/src/RewindTheater.ts b/libs/web-player/rewind/src/CommonManagers.ts
similarity index 92%
rename from libs/web-player/rewind/src/RewindTheater.ts
rename to libs/web-player/rewind/src/CommonManagers.ts
index 47aa7f98..2af6864f 100644
--- a/libs/web-player/rewind/src/RewindTheater.ts
+++ b/libs/web-player/rewind/src/CommonManagers.ts
@@ -25,7 +25,7 @@ import { SkinSettingsStore } from "./services/SkinSettingsStore";
* Example: Preferred skin can be set at only one place and is shared among all tools.
*/
@injectable()
-export class RewindTheater {
+export class CommonManagers {
constructor(
public readonly skinManager: SkinManager,
public readonly skinSettingsStore: SkinSettingsStore,
@@ -37,6 +37,7 @@ export class RewindTheater {
private readonly rewindLocalStorage: RewindLocalStorage,
) {}
+ // This should only be called after there is a connection to the backend.
async initialize() {
this.rewindLocalStorage.initialize();
await this.skinManager.loadPreferredSkin();
@@ -70,10 +71,12 @@ export function createRewindTheater({ apiUrl }: Settings) {
container.bind(RewindLocalStorage).toSelf();
// Theater facade
- container.bind(RewindTheater).toSelf();
+ container.bind(CommonManagers).toSelf();
return {
- theater: container.get(RewindTheater),
+ common: container.get(CommonManagers),
analyzer: createRewindAnalysisApp(container),
};
}
+
+export type RewindTheater = ReturnType;
diff --git a/libs/web-player/rewind/src/core/api/BackendStatusService.ts b/libs/web-player/rewind/src/core/api/BackendStatusService.ts
new file mode 100644
index 00000000..99003b7b
--- /dev/null
+++ b/libs/web-player/rewind/src/core/api/BackendStatusService.ts
@@ -0,0 +1,18 @@
+import { inject, injectable } from "inversify";
+import { TYPES } from "../../types/types";
+import { BehaviorSubject } from "rxjs";
+
+export type BackendState = "NOT_STARTED" | "SETUP_MISSING" | "LOADING" | "READY";
+
+@injectable()
+export class BackendStatusService {
+ status$: BehaviorSubject;
+
+ constructor(@inject(TYPES.API_URL) private readonly apiUrl: string) {
+ this.status$ = new BehaviorSubject("NOT_STARTED");
+ }
+
+ async wait() {
+ await fetch(`${this.apiUrl}/status`);
+ }
+}
diff --git a/libs/web-player/rewind/src/creators/createRewindAnalysisApp.ts b/libs/web-player/rewind/src/creators/createRewindAnalysisApp.ts
index fc725a83..e27f7d23 100644
--- a/libs/web-player/rewind/src/creators/createRewindAnalysisApp.ts
+++ b/libs/web-player/rewind/src/creators/createRewindAnalysisApp.ts
@@ -41,9 +41,9 @@ import { ClipRecorder } from "../apps/analysis/manager/ClipRecorder";
*
* The analysis tool can be used as a standalone app though.
*/
-export function createRewindAnalysisApp(rewindTheaterContainer: Container) {
+export function createRewindAnalysisApp(commonContainer: Container) {
const container = new Container({ defaultScope: "Singleton" });
- container.parent = rewindTheaterContainer;
+ container.parent = commonContainer;
container.bind(STAGE_TYPES.EVENT_EMITTER).toConstantValue(new EventEmitter2());
// TODO
container.bind(TYPES.WS_URL).toConstantValue("http://localhost:7271");
diff --git a/libs/web-player/rewind/src/index.ts b/libs/web-player/rewind/src/index.ts
index 13262145..138b04d0 100644
--- a/libs/web-player/rewind/src/index.ts
+++ b/libs/web-player/rewind/src/index.ts
@@ -1,5 +1,5 @@
-export { createRewindTheater } from "./RewindTheater";
-export { AnalysisApp } from "./apps/analysis/AnalysisApp";
+export * from "./CommonManagers";
+export * from "./apps/analysis/AnalysisApp";
export * from "./core/game/GameplayClock";
export * from "./model/SkinId";