Add loading window functionality with HTML and update application controller

This commit is contained in:
2026-06-04 03:07:40 +02:00
parent 0ea4c6e01b
commit 5da609cce4
4 changed files with 68 additions and 8 deletions
+8 -5
View File
@@ -13,6 +13,7 @@ export type ApplicationWindow = {
isDestroyed: () => boolean; isDestroyed: () => boolean;
isMinimized: () => boolean; isMinimized: () => boolean;
loadURL: (url: string) => Promise<unknown>; loadURL: (url: string) => Promise<unknown>;
loadFile: (filePath: string) => Promise<unknown>;
restore: () => void; restore: () => void;
show: () => void; show: () => void;
}; };
@@ -119,6 +120,13 @@ export function createApplicationController({
deps.setAppUserModelId(appConfig.userModelId); deps.setAppUserModelId(appConfig.userModelId);
} }
mainWindow = deps.createMainWindow();
loadingWindow = deps.createLoadingWindow();
await loadingWindow.loadFile(paths.staticLoadingHtmlPath);
loadingWindow.show();
await sleep(50);
state = "preparing"; state = "preparing";
const preparedRuntime = deps.prepareRuntime({ const preparedRuntime = deps.prepareRuntime({
sourceRuntimePath: paths.sourceNodecgRuntimePath, sourceRuntimePath: paths.sourceNodecgRuntimePath,
@@ -131,11 +139,6 @@ export function createApplicationController({
nodecgManager = deps.createNodecgProcessManager(preparedRuntime.runtimePath); nodecgManager = deps.createNodecgProcessManager(preparedRuntime.runtimePath);
mainWindow = deps.createMainWindow();
loadingWindow = deps.createLoadingWindow();
loadingWindow.show();
state = "starting"; state = "starting";
await startNodecg(); await startNodecg();
+2
View File
@@ -9,6 +9,7 @@ export type ApplicationPaths = {
nodecgBaseUrl: string; nodecgBaseUrl: string;
mainDashboardUrl: string; mainDashboardUrl: string;
loadingDashboardUrl: string; loadingDashboardUrl: string;
staticLoadingHtmlPath: string;
}; };
export function getRootPath(isDev: boolean, compiledMainDir: string, resourcesPath: string): string { export function getRootPath(isDev: boolean, compiledMainDir: string, resourcesPath: string): string {
@@ -78,5 +79,6 @@ export function getApplicationPaths({
nodecgBaseUrl: getNodecgBaseUrl(appConfig.nodecgPort), nodecgBaseUrl: getNodecgBaseUrl(appConfig.nodecgPort),
mainDashboardUrl: getDashboardUrl(appConfig.nodecgPort, appConfig.bundleName, appConfig.mainDashboardRoute), mainDashboardUrl: getDashboardUrl(appConfig.nodecgPort, appConfig.bundleName, appConfig.mainDashboardRoute),
loadingDashboardUrl: getDashboardUrl(appConfig.nodecgPort, appConfig.bundleName, appConfig.loadingDashboardRoute), loadingDashboardUrl: getDashboardUrl(appConfig.nodecgPort, appConfig.bundleName, appConfig.loadingDashboardRoute),
staticLoadingHtmlPath: path.join(rootPath, "static", "loading.html"),
}; };
} }
+15 -3
View File
@@ -35,6 +35,10 @@ class MockWindow implements ApplicationWindow {
this.events.push(`${this.name}:load:${url}`); this.events.push(`${this.name}:load:${url}`);
} }
async loadFile(filePath: string): Promise<void> {
this.events.push(`${this.name}:loadFile:${filePath}`);
}
restore(): void { restore(): void {
this.events.push(`${this.name}:restore`); this.events.push(`${this.name}:restore`);
this.minimized = false; this.minimized = false;
@@ -87,6 +91,7 @@ test("ApplicationController preserves startup ordering and schedules updates aft
nodecgBaseUrl: "http://127.0.0.1:9090", nodecgBaseUrl: "http://127.0.0.1:9090",
mainDashboardUrl: "http://localhost:9090/bundles/scoreko-dev/dashboard/main.html?standalone=true", mainDashboardUrl: "http://localhost:9090/bundles/scoreko-dev/dashboard/main.html?standalone=true",
loadingDashboardUrl: "http://localhost:9090/bundles/scoreko-dev/dashboard/loading/main.html?standalone=true", loadingDashboardUrl: "http://localhost:9090/bundles/scoreko-dev/dashboard/loading/main.html?standalone=true",
staticLoadingHtmlPath: "/app/static/loading.html",
}; };
const controller = createApplicationController({ const controller = createApplicationController({
@@ -129,11 +134,13 @@ test("ApplicationController preserves startup ordering and schedules updates aft
assert.equal(controller.getState(), "ready"); assert.equal(controller.getState(), "ready");
assert.deepEqual(events, [ assert.deepEqual(events, [
"set-app-user-model-id", "set-app-user-model-id",
"prepare-runtime",
"create-manager",
"create-main", "create-main",
"create-loading", "create-loading",
`loading:loadFile:${paths.staticLoadingHtmlPath}`,
"loading:show", "loading:show",
"sleep:50",
"prepare-runtime",
"create-manager",
"start-nodecg", "start-nodecg",
"wait-nodecg", "wait-nodecg",
`loading:load:${paths.loadingDashboardUrl}`, `loading:load:${paths.loadingDashboardUrl}`,
@@ -158,6 +165,7 @@ test("ApplicationController directly launches packaged app after runtime install
nodecgBaseUrl: "http://127.0.0.1:9090", nodecgBaseUrl: "http://127.0.0.1:9090",
mainDashboardUrl: "http://localhost:9090/main", mainDashboardUrl: "http://localhost:9090/main",
loadingDashboardUrl: "http://localhost:9090/loading", loadingDashboardUrl: "http://localhost:9090/loading",
staticLoadingHtmlPath: "/app/static/loading.html",
}, },
deps: { deps: {
createLoadingWindow: () => { createLoadingWindow: () => {
@@ -189,10 +197,12 @@ test("ApplicationController directly launches packaged app after runtime install
assert.equal(controller.getState(), "ready"); assert.equal(controller.getState(), "ready");
assert.deepEqual(events, [ assert.deepEqual(events, [
"create-manager",
"create-main", "create-main",
"create-loading", "create-loading",
"loading:loadFile:/app/static/loading.html",
"loading:show", "loading:show",
"sleep:50",
"create-manager",
"start-nodecg", "start-nodecg",
"wait-nodecg", "wait-nodecg",
"loading:load:http://localhost:9090/loading", "loading:load:http://localhost:9090/loading",
@@ -217,6 +227,7 @@ test("ApplicationController activation before readiness routes through launch",
nodecgBaseUrl: "http://127.0.0.1:9090", nodecgBaseUrl: "http://127.0.0.1:9090",
mainDashboardUrl: "http://localhost:9090/main", mainDashboardUrl: "http://localhost:9090/main",
loadingDashboardUrl: "http://localhost:9090/loading", loadingDashboardUrl: "http://localhost:9090/loading",
staticLoadingHtmlPath: "/app/static/loading.html",
}, },
deps: { deps: {
createLoadingWindow: () => new MockWindow("loading", events), createLoadingWindow: () => new MockWindow("loading", events),
@@ -257,6 +268,7 @@ test("ApplicationController shutdown is idempotent", async () => {
nodecgBaseUrl: "http://127.0.0.1:9090", nodecgBaseUrl: "http://127.0.0.1:9090",
mainDashboardUrl: "http://localhost:9090/main", mainDashboardUrl: "http://localhost:9090/main",
loadingDashboardUrl: "http://localhost:9090/loading", loadingDashboardUrl: "http://localhost:9090/loading",
staticLoadingHtmlPath: "/app/static/loading.html",
}, },
deps: { deps: {
createLoadingWindow: () => new MockWindow("loading", events), createLoadingWindow: () => new MockWindow("loading", events),
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Scoreko</title>
<style>
body {
background-color: #0f0f0f;
color: #ffffff;
font-family: system-ui, -apple-system, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
margin: 0;
overflow: hidden;
user-select: none;
}
.spinner {
width: 40px;
height: 40px;
border: 4px solid rgba(255, 255, 255, 0.1);
border-left-color: #ffffff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
p {
margin: 0;
font-size: 14px;
opacity: 0.8;
}
</style>
</head>
<body>
<div class="spinner"></div>
<p>Preparando Scoreko...</p>
</body>
</html>