mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
set auto update AND fix download version errors
This commit is contained in:
@@ -164,6 +164,20 @@ const configuration: webpack.Configuration = {
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
nodeModules: webpackPaths.appNodeModulesPath,
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: path.join('launcher.html'),
|
||||
template: path.join(webpackPaths.srcRendererPath, 'launcher.ejs'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: false,
|
||||
env: process.env.NODE_ENV,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
nodeModules: webpackPaths.appNodeModulesPath,
|
||||
})
|
||||
],
|
||||
|
||||
node: {
|
||||
|
||||
@@ -143,6 +143,18 @@ const configuration: webpack.Configuration = {
|
||||
isBrowser: false,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'launcher.html',
|
||||
template: path.join(webpackPaths.srcRendererPath, 'launcher.ejs'),
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true,
|
||||
},
|
||||
isBrowser: false,
|
||||
isDevelopment: process.env.NODE_ENV !== 'production',
|
||||
})
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -108,14 +108,10 @@
|
||||
}
|
||||
},
|
||||
"errors":{
|
||||
"titles":{
|
||||
"already-downloading": "A download is already in progress",
|
||||
"verification-failed":"The verification failed.",
|
||||
"no-internet": "No internet connection."
|
||||
},
|
||||
"msg":{
|
||||
"Password": "Password is invalid.",
|
||||
"InvalidCredentials": "Your e-mail or password is invalid 😴",
|
||||
"InvalidPassword": "Your password is invalid 😕",
|
||||
"NoManifest": "No manifest was found",
|
||||
"DirectoryCreate": "Unable to install the necessary folders.",
|
||||
"NotAvailableApp": "Are you trying to download BeatSaber when you don't have it ? 🤣",
|
||||
@@ -134,7 +130,9 @@
|
||||
"ConnectionError": "Unable to connect to Steam after 10 tries 🤯",
|
||||
"LicenceError": "Unable to get the list of licenses.",
|
||||
"verification-failed": "Verification failed, try again later.",
|
||||
"RateLimitExceeded": "You've tried too many times, wait a while and try again later."
|
||||
"RateLimitExceeded": "You've tried too many times, wait a while and try again later.",
|
||||
"AlreadyDownloading": "A download is already in progress",
|
||||
"no-internet": "No internet connection."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -260,6 +258,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"auto-update":{
|
||||
"checking": "Checking for updates",
|
||||
"downloading": "Downloading updates"
|
||||
},
|
||||
"dateformat":{
|
||||
"dayNames": [
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
|
||||
|
||||
@@ -108,14 +108,10 @@
|
||||
}
|
||||
},
|
||||
"errors":{
|
||||
"titles":{
|
||||
"already-downloading": "La descarga ya está en curso",
|
||||
"verification-failed":"La verificación falló.",
|
||||
"no-internet": "Sin conexión a Internet."
|
||||
},
|
||||
"msg":{
|
||||
"Password": "La contraseña es inválida.",
|
||||
"InvalidCredentials": "Su correo electrónico o contraseña no son válidos 😴",
|
||||
"InvalidPassword": "Su contraseña no es válida 😕",
|
||||
"NoManifest": "No se ha encontrado el manifiesto",
|
||||
"DirectoryCreate": "No se pueden instalar las carpetas necesarias.",
|
||||
"NotAvailableApp": "¿Intentas descargar BeatSaber cuando no lo tienes? 🤣",
|
||||
@@ -134,7 +130,9 @@
|
||||
"ConnectionError": "No se puede conectar a Steam después de 10 intentos 🤯",
|
||||
"LicenceError": "No se puede obtener la lista de licencias.",
|
||||
"verification-failed": "Verificación fallida, inténtelo más tarde.",
|
||||
"RateLimitExceeded": "Lo has intentado demasiadas veces, espera un poco y vuelve a intentarlo más tarde."
|
||||
"RateLimitExceeded": "Lo has intentado demasiadas veces, espera un poco y vuelve a intentarlo más tarde.",
|
||||
"AlreadyDownloading": "La descarga ya está en curso",
|
||||
"no-internet": "Sin conexión a Internet."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -260,6 +258,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"auto-update":{
|
||||
"checking": "Comprobar las actualizaciones",
|
||||
"downloading": "Descargar actualizaciones"
|
||||
},
|
||||
"dateformat":{
|
||||
"dayNames": [
|
||||
"Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb",
|
||||
|
||||
@@ -108,14 +108,10 @@
|
||||
}
|
||||
},
|
||||
"errors":{
|
||||
"titles":{
|
||||
"already-downloading": "Un téléchargement est déjà en cours",
|
||||
"verification-failed": "La vérification a échoué.",
|
||||
"no-internet": "Pas de connexion internet."
|
||||
},
|
||||
"msg":{
|
||||
"Password": "Le mot de passe est invalide.",
|
||||
"InvalidCredentials": "Ton e-mail ou mot de passe est invalide 😴",
|
||||
"InvalidPassword": "Ton mot de passe est invalide 😕",
|
||||
"NoManifest": "Aucun manifest n'a été trouvé.",
|
||||
"DirectoryCreate": "Impossible d'installer les dossiers nécessaires.",
|
||||
"NotAvailableApp": "Tu essayes de télécharger BeatSaber alors que tu ne l'as pas ? 🤣",
|
||||
@@ -134,7 +130,9 @@
|
||||
"ConnectionError": "Impossible de se connecter à Steam après 10 essais 🤯",
|
||||
"LicenceError": "Impossible d'obtenir la liste des licences.",
|
||||
"verification-failed": "La vérification a échoué, réessaye plus tard.",
|
||||
"RateLimitExceeded": "Tu as essayé trop de fois attend un peu et recommence plus tard."
|
||||
"RateLimitExceeded": "Tu as essayé trop de fois attend un peu et recommence plus tard.",
|
||||
"AlreadyDownloading": "Un téléchargement est déjà en cours",
|
||||
"no-internet": "Pas de connexion internet."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -260,6 +258,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"auto-update":{
|
||||
"checking": "Vérification des mises à jour",
|
||||
"downloading": "Téléchargement des mises à jour"
|
||||
},
|
||||
"dateformat":{
|
||||
"dayNames": [
|
||||
"Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam",
|
||||
|
||||
Generated
+14
-4
@@ -3249,6 +3249,7 @@
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.0.3.tgz",
|
||||
"integrity": "sha512-SfG2wnyjpUbbdtpnqDpWwklujofC6GarGpvdWrEkg9p5AD/xJmTF2buTNaqs3qtsNBEVQDDjZz9xc2GGpVyMfA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.3.4",
|
||||
"sax": "^1.2.4"
|
||||
@@ -5180,12 +5181,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"electron-updater": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.2.1.tgz",
|
||||
"integrity": "sha512-OQZVIvqcK8j03HjT07uVPgvguP/r8RY2wZcwCM26+fcDOjtrm01Dfz3G8Eru+69znbrR+F9pDzr98ewMavBrWQ==",
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-5.2.4.tgz",
|
||||
"integrity": "sha512-AE+I4cEagOJvHvtkBvJCp+hu1mrpinCt7PMmEOsDcpfayrPvWLuxeFVR9BzRvZVbz0eAqpRQjcEuR8gK80K7lQ==",
|
||||
"requires": {
|
||||
"@types/semver": "^7.3.6",
|
||||
"builder-util-runtime": "9.0.3",
|
||||
"builder-util-runtime": "9.1.1",
|
||||
"fs-extra": "^10.0.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lazy-val": "^1.0.5",
|
||||
@@ -5195,6 +5196,15 @@
|
||||
"typed-emitter": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"builder-util-runtime": {
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.1.1.tgz",
|
||||
"integrity": "sha512-azRhYLEoDvRDR8Dhis4JatELC/jUvYjm4cVSj7n9dauGTOM2eeNn9KS0z6YA6oDsjI1xphjNbY6PZZeHPzzqaw==",
|
||||
"requires": {
|
||||
"debug": "^4.3.4",
|
||||
"sax": "^1.2.4"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
||||
|
||||
+4
-4
@@ -13,7 +13,8 @@
|
||||
"start:main": "cross-env NODE_ENV=development electronmon -r ts-node/register/transpile-only ./src/main/main.ts",
|
||||
"start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.preload.dev.ts",
|
||||
"start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"publish": "npm run build && electron-builder --publish always --win --x64"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,jsx,ts,tsx}": [
|
||||
@@ -90,8 +91,7 @@
|
||||
},
|
||||
"publish": {
|
||||
"provider": "github",
|
||||
"owner": "Zagrios",
|
||||
"repo": "bs-manager"
|
||||
"owner": "Zagrios"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
@@ -228,7 +228,7 @@
|
||||
"electron-debug": "^3.2.0",
|
||||
"electron-log": "^4.4.8",
|
||||
"electron-store": "^8.1.0",
|
||||
"electron-updater": "^5.2.1",
|
||||
"electron-updater": "^5.2.4",
|
||||
"framer-motion": "^7.2.1",
|
||||
"history": "^5.3.0",
|
||||
"is-online": "^9.0.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "BSManager",
|
||||
"version": "0.1.0",
|
||||
"version": "0.0.8",
|
||||
"description": "A foundation for scalable desktop apps",
|
||||
"main": "./dist/main/main.js",
|
||||
"author": {
|
||||
|
||||
@@ -49,10 +49,8 @@ ipcMain.on('bs-download.installation-folder', async (event, request: IpcRequest<
|
||||
ipcMain.on('bs-download.set-installation-folder', (event, request: IpcRequest<string>) => {
|
||||
const installerService = InstallationLocationService.getInstance();
|
||||
installerService.setInstallationDirectory(request.args).then(res => {
|
||||
console.log("déplacement terminer");
|
||||
UtilsService.getInstance().ipcSend(request.responceChannel, {success: true, data: res});
|
||||
}).catch((err: BsmException) => {
|
||||
console.log(err);
|
||||
UtilsService.getInstance().ipcSend(request.responceChannel, {success: false, error: err});
|
||||
});
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@ ipcMain.on('bs-launch.launch', (event, request: IpcRequest<LauchOption>) => {
|
||||
const utilsService = UtilsService.getInstance();
|
||||
|
||||
launcherService.launch(request.args).then(res => {
|
||||
console.log("BEAT SABER LANCER");
|
||||
utilsService.ipcSend(request.responceChannel, {success: true, data: res});
|
||||
}).catch((err: BsmException) => {
|
||||
utilsService.ipcSend(request.responceChannel, {success: false, error: err});
|
||||
|
||||
@@ -35,20 +35,16 @@ ipcMain.on("bs-version.open-folder", async (event, req: IpcRequest<BSVersion>) =
|
||||
|
||||
ipcMain.on("bs-version.edit", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => {
|
||||
BSLocalVersionService.getInstance().editVersion(req.args.version, req.args.name, req.args.color).then(res => {
|
||||
console.log(res);
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, {success: !!res, data: res});
|
||||
}).catch((error: BsmException) => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, {success: false, error});
|
||||
console.log(error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("bs-version.clone", async (event, req: IpcRequest<{version: BSVersion, name: string, color: string}>) => {
|
||||
BSLocalVersionService.getInstance().cloneVersion(req.args.version, req.args.name, req.args.color).then(res => {
|
||||
console.log(res);
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, {success: !!res, data: res});
|
||||
}).catch((error: BsmException) => {
|
||||
UtilsService.getInstance().ipcSend(req.responceChannel, {success: false, error});
|
||||
console.log(error);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,3 +5,5 @@ import './bs-version-ipcs';
|
||||
import './bs-uninstall-ipcs';
|
||||
import './map-ipcs';
|
||||
import './supporters-ipcs';
|
||||
import './launcher-ipcs';
|
||||
import './window-manager-ipcs';
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { AutoUpdaterService } from "../services/auto-updater.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { UtilsService } from "../services/utils.service";
|
||||
|
||||
ipcMain.on("download-update", async (event, request: IpcRequest<void>) => {
|
||||
|
||||
const updaterService = AutoUpdaterService.getInstance();
|
||||
const utilsService = UtilsService.getInstance();
|
||||
|
||||
updaterService.downloadUpdate().then(res => utilsService.ipcSend(request.responceChannel, {success: res}))
|
||||
.catch(() => utilsService.ipcSend(request.responceChannel, {success: false}));
|
||||
|
||||
});
|
||||
|
||||
ipcMain.on("check-update", async (event, request: IpcRequest<void>) => {
|
||||
|
||||
const updaterService = AutoUpdaterService.getInstance();
|
||||
const utilsService = UtilsService.getInstance();
|
||||
|
||||
updaterService.isUpdateAvailable().then(updateAvailable => {
|
||||
utilsService.ipcSend(request.responceChannel, {success: true, data: updateAvailable});
|
||||
})
|
||||
.catch(() => utilsService.ipcSend(request.responceChannel, {success: false}));
|
||||
|
||||
});
|
||||
|
||||
ipcMain.on("install-update", async (event, request: IpcRequest<void>) => {
|
||||
const updaterService = AutoUpdaterService.getInstance();
|
||||
updaterService.quitAndInstall();
|
||||
});
|
||||
@@ -1,26 +1,29 @@
|
||||
import { ipcMain, shell, dialog, app } from 'electron';
|
||||
import { UtilsService } from '../services/utils.service';
|
||||
import { IpcRequest } from 'shared/models/ipc';
|
||||
import { getMainWindow } from '../main';
|
||||
|
||||
ipcMain.on('window.close', async () => {
|
||||
getMainWindow()?.close();
|
||||
const utils = UtilsService.getInstance();
|
||||
utils.getMainWindow()?.close();
|
||||
});
|
||||
|
||||
ipcMain.on('window.maximize', async () => {
|
||||
getMainWindow()?.maximize();
|
||||
const utils = UtilsService.getInstance();
|
||||
utils.getMainWindow()?.maximize();
|
||||
});
|
||||
|
||||
ipcMain.on('window.minimize', async () => {
|
||||
getMainWindow()?.minimize();
|
||||
const utils = UtilsService.getInstance();
|
||||
utils.getMainWindow()?.minimize();
|
||||
});
|
||||
|
||||
ipcMain.on('window.reset', async () => {
|
||||
getMainWindow()?.restore();
|
||||
const utils = UtilsService.getInstance();
|
||||
utils.getMainWindow()?.restore();
|
||||
});
|
||||
|
||||
ipcMain.on('new-window', async (event, request: IpcRequest<string>) => {
|
||||
shell.openExternal(request.args);
|
||||
shell.openExternal(request.args);
|
||||
});
|
||||
|
||||
ipcMain.on('choose-folder', async (event, request: IpcRequest<void>) => {
|
||||
@@ -30,7 +33,8 @@ ipcMain.on('choose-folder', async (event, request: IpcRequest<void>) => {
|
||||
});
|
||||
|
||||
ipcMain.on("window.progression", async (event, request: IpcRequest<number>) => {
|
||||
getMainWindow().setProgressBar(request.args / 100);
|
||||
const utils = UtilsService.getInstance();
|
||||
utils.getMainWindow().setProgressBar(request.args / 100);
|
||||
});
|
||||
|
||||
ipcMain.on('save-file', async (event, request: IpcRequest<{filename?: string, filters?: Electron.FileFilter[]}>) => {
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { ipcMain } from "electron";
|
||||
import { WindowManagerService } from "../services/window-manager.service";
|
||||
import { IpcRequest } from "shared/models/ipc";
|
||||
import { AppWindow } from "shared/models/window-manager/app-window.model";
|
||||
|
||||
ipcMain.on("open-window-then-close-all", async (event, request: IpcRequest<AppWindow>) => {
|
||||
const windowManager = WindowManagerService.getInstance();
|
||||
|
||||
windowManager.openWindow(request.args).then(window => {
|
||||
windowManager.closeAllWindows(request.args);
|
||||
});
|
||||
});
|
||||
+20
-103
@@ -9,19 +9,15 @@
|
||||
* `./src/main.js` using webpack. This gives us some performance wins.
|
||||
*/
|
||||
import path from 'path';
|
||||
import { app, BrowserWindow, shell } from 'electron';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import { app } from 'electron';
|
||||
import log from 'electron-log';
|
||||
import { resolveHtmlPath } from './util';
|
||||
import './ipcs';
|
||||
import { UtilsService } from './services/utils.service';
|
||||
import { WindowManagerService } from './services/window-manager.service';
|
||||
|
||||
export default class AppUpdater {
|
||||
constructor() {
|
||||
autoUpdater.logger = log;
|
||||
//autoUpdater.checkForUpdatesAndNotify();
|
||||
}
|
||||
}
|
||||
export const PRELOAD_PATH = app.isPackaged ? path.join(__dirname, 'preload.js') : path.join(__dirname, '../../.erb/dll/preload.js')
|
||||
|
||||
const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
|
||||
|
||||
log.transports.file.level = 'info';
|
||||
log.transports.file.resolvePath = (() => {
|
||||
@@ -31,11 +27,8 @@ log.transports.file.resolvePath = (() => {
|
||||
|
||||
log.catchErrors();
|
||||
|
||||
let mainWindow: BrowserWindow = null;
|
||||
|
||||
export function getMainWindow(): BrowserWindow{
|
||||
return mainWindow;
|
||||
}
|
||||
const utilsService = UtilsService.getInstance();
|
||||
utilsService.setAssetsPath(app.isPackaged ? path.join(process.resourcesPath, 'assets') : path.join(__dirname, '../../assets'));
|
||||
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
@@ -43,107 +36,31 @@ if (process.env.NODE_ENV === 'production') {
|
||||
sourceMapSupport.install();
|
||||
}
|
||||
|
||||
const isDebug = process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
|
||||
|
||||
if (isDebug) {
|
||||
require('electron-debug')();
|
||||
}
|
||||
|
||||
const installExtensions = async () => {
|
||||
const installer = require('electron-devtools-installer');
|
||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
||||
const extensions = ['REACT_DEVELOPER_TOOLS'];
|
||||
const installer = require('electron-devtools-installer');
|
||||
const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
|
||||
const extensions = ['REACT_DEVELOPER_TOOLS'];
|
||||
|
||||
return installer
|
||||
.default(
|
||||
extensions.map((name) => installer[name]),
|
||||
forceDownload
|
||||
)
|
||||
.catch(console.log);
|
||||
return installer.default(extensions.map((name) => installer[name]), forceDownload).catch(console.log);
|
||||
};
|
||||
|
||||
const createWindow = async () => {
|
||||
if (isDebug) {
|
||||
await installExtensions();
|
||||
}
|
||||
|
||||
const RESOURCES_PATH = app.isPackaged ? path.join(process.resourcesPath, 'assets') : path.join(__dirname, '../../assets');
|
||||
|
||||
UtilsService.getInstance().setAssetsPath(RESOURCES_PATH);
|
||||
|
||||
const getAssetPath = (...paths: string[]): string => {
|
||||
return path.join(RESOURCES_PATH, ...paths);
|
||||
};
|
||||
|
||||
mainWindow = new BrowserWindow({
|
||||
show: false,
|
||||
width: 1080,
|
||||
height: 720,
|
||||
minWidth: 900,
|
||||
minHeight: 500,
|
||||
frame: false,
|
||||
titleBarOverlay: false,
|
||||
icon: getAssetPath('favicon.ico'),
|
||||
webPreferences: {
|
||||
preload: app.isPackaged
|
||||
? path.join(__dirname, 'preload.js')
|
||||
: path.join(__dirname, '../../.erb/dll/preload.js'),
|
||||
},
|
||||
});
|
||||
|
||||
UtilsService.getInstance().setMainWindow(mainWindow);
|
||||
|
||||
mainWindow.loadURL(resolveHtmlPath('index.html'));
|
||||
|
||||
mainWindow.on('ready-to-show', () => {
|
||||
if (!mainWindow) {
|
||||
throw new Error('"mainWindow" is not defined');
|
||||
}
|
||||
if (process.env.START_MINIMIZED) {
|
||||
mainWindow.minimize();
|
||||
} else {
|
||||
mainWindow.show();
|
||||
}
|
||||
});
|
||||
|
||||
mainWindow.on('closed', () => {
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
mainWindow.removeMenu();
|
||||
mainWindow.setMenu(null);
|
||||
|
||||
// Open urls in the user's browser
|
||||
mainWindow.webContents.setWindowOpenHandler((edata) => {
|
||||
shell.openExternal(edata.url);
|
||||
return { action: 'deny' };
|
||||
});
|
||||
|
||||
// Remove this if your app does not use auto updates
|
||||
// eslint-disable-next-line
|
||||
new AppUpdater();
|
||||
if(isDebug){ await installExtensions(); }
|
||||
WindowManagerService.getInstance().openWindow("launcher.html");
|
||||
};
|
||||
|
||||
/**
|
||||
* Add event listeners...
|
||||
*/
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
// Respect the OSX convention of having the application in memory even
|
||||
// after all windows have been closed
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
// Respect the OSX convention of having the application in memory even
|
||||
// after all windows have been closed
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app
|
||||
.whenReady()
|
||||
.then(() => {
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) createWindow();
|
||||
});
|
||||
})
|
||||
.catch(console.log);
|
||||
}).catch(console.log);
|
||||
@@ -0,0 +1,55 @@
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import log from 'electron-log';
|
||||
import { UtilsService } from './utils.service';
|
||||
export class AutoUpdaterService {
|
||||
|
||||
private static instance: AutoUpdaterService;
|
||||
|
||||
private readonly utilsService: UtilsService;
|
||||
|
||||
public static getInstance(): AutoUpdaterService{
|
||||
if(!AutoUpdaterService.instance){ AutoUpdaterService.instance = new AutoUpdaterService(); }
|
||||
return AutoUpdaterService.instance;
|
||||
}
|
||||
|
||||
constructor(){
|
||||
autoUpdater.logger = log;
|
||||
autoUpdater.autoDownload = false;
|
||||
|
||||
this.utilsService = UtilsService.getInstance();
|
||||
}
|
||||
|
||||
public isUpdateAvailable(): Promise<boolean>{
|
||||
return new Promise(resolve => {
|
||||
autoUpdater.checkForUpdates().then(info => {
|
||||
const needUpdate = (() => {
|
||||
if(!info || !info.updateInfo){ return false; }
|
||||
if(autoUpdater.currentVersion.version === info.updateInfo.version){ return false; }
|
||||
return true;
|
||||
})();
|
||||
resolve(needUpdate)}
|
||||
).catch(() => resolve(false));
|
||||
});
|
||||
}
|
||||
|
||||
public downloadUpdate(): Promise<boolean>{
|
||||
|
||||
autoUpdater.removeAllListeners("download-progress");
|
||||
autoUpdater.addListener("download-progress", info => {
|
||||
this.utilsService.ipcSend("update-download-progress", {success: true, data: info.percent});
|
||||
});
|
||||
// const promise = new Promise<boolean>((resolve, reject) => {
|
||||
// autoUpdater.addListener("update-downloaded", () => resolve(true));
|
||||
// autoUpdater.addListener("error", () => reject(false))
|
||||
// });
|
||||
|
||||
return autoUpdater.downloadUpdate().then(res => !!res && !!res.length);
|
||||
}
|
||||
|
||||
public quitAndInstall(){
|
||||
autoUpdater.quitAndInstall();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import log from "electron-log";
|
||||
import { InstallationLocationService } from "./installation-location.service";
|
||||
import { ctrlc } from "ctrlc-windows";
|
||||
import { BSLocalVersionService } from "./bs-local-version.service";
|
||||
import { getMainWindow } from "../main";
|
||||
import isOnline from 'is-online';
|
||||
|
||||
export class BSInstallerService{
|
||||
@@ -25,7 +24,7 @@ export class BSInstallerService{
|
||||
this.installLocationService = InstallationLocationService.getInstance();
|
||||
this.localVersionService = BSLocalVersionService.getInstance();
|
||||
|
||||
getMainWindow().on("close", () => {
|
||||
this.utils.getMainWindow().on("close", () => {
|
||||
this.killDownloadProcess();
|
||||
});
|
||||
}
|
||||
@@ -35,14 +34,16 @@ export class BSInstallerService{
|
||||
return BSInstallerService.instance;
|
||||
}
|
||||
|
||||
private getDepotDownloaderExePath(): string{
|
||||
return path.join(this.utils.getAssetsScriptsPath(), 'depot-downloader', 'DepotDownloader.exe');
|
||||
}
|
||||
private getDepotDownloaderExePath(): string{
|
||||
return path.join(this.utils.getAssetsScriptsPath(), 'depot-downloader', 'DepotDownloader.exe');
|
||||
}
|
||||
|
||||
private sendDownloadEvent(event: DownloadEventType, data?: string|number, success = true): void{
|
||||
if(typeof data === "string"){ data = data.replaceAll(/\[|\]/g, ""); }
|
||||
this.utils.ipcSend(`bs-download.${event}`, { success, data });
|
||||
}
|
||||
private removeSpecialSchar(txt: string): string{ return txt.replaceAll(/\[|\]/g, ""); }
|
||||
|
||||
private sendDownloadEvent(event: DownloadEventType, data?: string|number, success = true): void{
|
||||
if(typeof data === "string"){ data = this.removeSpecialSchar(data); }
|
||||
this.utils.ipcSend(`bs-download.${event}`, { success, data });
|
||||
}
|
||||
|
||||
public sendInputProcess(input: string){
|
||||
if(this.downloadProcess.stdin.writable){
|
||||
@@ -54,16 +55,16 @@ export class BSInstallerService{
|
||||
return new Promise(resolve => {
|
||||
if(this.downloadProcess?.killed && !this.downloadProcess?.pid){ return resolve(false); }
|
||||
|
||||
this.downloadProcess.on('close', () => resolve(true));
|
||||
this.downloadProcess.once('exit', () => resolve(true));
|
||||
|
||||
ctrlc(this.downloadProcess.pid);
|
||||
if(!this.downloadProcess.kill()){ return resolve(false); }
|
||||
setTimeout(() => resolve(false), 2000);
|
||||
setTimeout(() => resolve(false), 3000);
|
||||
});
|
||||
}
|
||||
|
||||
public async downloadBsVersion(downloadInfos: DownloadInfo): Promise<DownloadEvent>{
|
||||
if(this.downloadProcess && !this.downloadProcess?.killed){ return {type: "[AlreadyDownloading]"}; }
|
||||
|
||||
if(this.downloadProcess && this.downloadProcess.connected){ throw "AlreadyDownloading"; }
|
||||
const {bsVersion} = downloadInfos;
|
||||
if(!bsVersion){ return {type: "[Error]"}; }
|
||||
if(!(await isOnline({timeout: 1500}))){ throw "no-internet"; }
|
||||
@@ -86,9 +87,10 @@ export class BSInstallerService{
|
||||
|
||||
this.downloadProcess.stdout.on('data', data => {
|
||||
const matched = (data.toString() as string).match(/(?:\[(.*?)\])\|(?:\[(.*?)\]\|)?(.*?)(?=$|\[)/gm) ?? [];
|
||||
console.log(data.toString());
|
||||
matched.forEach(match => {
|
||||
const out = match.split("|");
|
||||
|
||||
if(out[0] !== "[Progress]" && out[0] !== "[Validated]"){ log.info(data.toString()); }
|
||||
|
||||
if(out[0] === "[Password]" as DownloadEventType && downloadInfos.password){
|
||||
this.sendInputProcess(downloadInfos.password);
|
||||
@@ -114,8 +116,7 @@ export class BSInstallerService{
|
||||
this.sendDownloadEvent("[Warning]", out[1]);
|
||||
}
|
||||
else if(out[0] === "[Error]" as DownloadEventType){
|
||||
reject(out[1]);
|
||||
this.sendDownloadEvent("[Error]", out[1], false);
|
||||
reject(this.removeSpecialSchar(out[1]));
|
||||
this.killDownloadProcess();
|
||||
log.error("Download Event, Error", data.toString());
|
||||
}
|
||||
@@ -125,18 +126,18 @@ export class BSInstallerService{
|
||||
|
||||
this.downloadProcess.stdout.on('error', (err) => {
|
||||
log.error("BS-DOWNLOAD ERROR", err.toString());
|
||||
this.downloadProcess.kill();
|
||||
reject(err);
|
||||
this.killDownloadProcess();
|
||||
reject();
|
||||
});
|
||||
this.downloadProcess.stderr.on('data', (err) => {
|
||||
log.error("BS-DOWNLOAD ERROR", err.toString());
|
||||
this.downloadProcess.kill();
|
||||
reject(err);
|
||||
this.killDownloadProcess();
|
||||
reject();
|
||||
});
|
||||
this.downloadProcess.stderr.on('error', (err) => {
|
||||
log.error("BS-DOWNLOAD ERROR", err.toString());
|
||||
this.downloadProcess.kill();
|
||||
reject(err);
|
||||
this.killDownloadProcess();
|
||||
reject();
|
||||
});
|
||||
|
||||
this.downloadProcess.on('close', () => reject());
|
||||
|
||||
@@ -38,6 +38,8 @@ export class BSLauncherService{
|
||||
const cwd = await this.localVersionService.getVersionPath(launchOptions.version);
|
||||
const exePath = path.join(cwd, BS_EXECUTABLE);
|
||||
|
||||
console.log(exePath);
|
||||
|
||||
if(!this.utilsService.pathExist(exePath)){ return "EXE_NOT_FINDED"; }
|
||||
|
||||
const launchMods = [launchOptions.oculus && "-vrmode oculus", launchOptions.desktop && "fpfc", launchOptions.debug && "--verbose"];
|
||||
|
||||
@@ -30,8 +30,6 @@ export class MapService{
|
||||
const versionPath = await this.localVersionService.getVersionPath(version);
|
||||
const mapsPath = this.getMapsPath(versionPath);
|
||||
|
||||
console.log(outputZip);
|
||||
|
||||
const output = createWriteStream(outputZip);
|
||||
const archive = archiver("zip", {zlib: {level: 9}});
|
||||
|
||||
|
||||
@@ -23,12 +23,13 @@ export class UtilsService{
|
||||
}
|
||||
|
||||
public setAssetsPath(path: string): void{ this.assetsPath = path; }
|
||||
public getAssetsPath(): string{ return this.assetsPath; }
|
||||
public getAssetsPath(pathToFile: string): string{ return path.join(this.assetsPath, pathToFile); }
|
||||
|
||||
public getAssetsScriptsPath(): string { return path.join(this.getAssetsPath(), 'scripts'); }
|
||||
public getAssestsJsonsPath(): string { return path.join(this.getAssetsPath(), 'jsons'); }
|
||||
public getAssetsScriptsPath(): string { return this.getAssetsPath("scripts") }
|
||||
public getAssestsJsonsPath(): string { return this.getAssetsPath("jsons"); }
|
||||
|
||||
public setMainWindow(win: BrowserWindow){ this.mainWindow = win; }
|
||||
public getMainWindow(){ return this.mainWindow; }
|
||||
|
||||
public pathExist(path: string): boolean{ return existsSync(path); }
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { app, BrowserWindow, BrowserWindowConstructorOptions } from "electron";
|
||||
import { resolveHtmlPath } from "../util";
|
||||
import { UtilsService } from "./utils.service";
|
||||
import { AppWindow } from "shared/models/window-manager/app-window.model";
|
||||
import { PRELOAD_PATH } from "../main";
|
||||
|
||||
export class WindowManagerService{
|
||||
|
||||
private static instance: WindowManagerService;
|
||||
|
||||
private readonly utilsService: UtilsService = UtilsService.getInstance();
|
||||
|
||||
private readonly appWindowsOptions: Record<AppWindow, BrowserWindowConstructorOptions> = {
|
||||
"launcher.html": {width: 380, height: 500, minWidth: 380, minHeight: 500, resizable: false},
|
||||
"index.html": {width: 1080, height: 720, minWidth: 900, minHeight: 500}
|
||||
}
|
||||
|
||||
private readonly baseWindowOption: BrowserWindowConstructorOptions = {
|
||||
icon: this.utilsService.getAssetsPath("favicon.ico"),
|
||||
show: false,
|
||||
frame: false,
|
||||
titleBarOverlay: false,
|
||||
webPreferences: { preload: PRELOAD_PATH }
|
||||
}
|
||||
|
||||
private readonly windows: Map<AppWindow, BrowserWindow> = new Map<AppWindow, BrowserWindow>();
|
||||
|
||||
public static getInstance(): WindowManagerService{
|
||||
if(!WindowManagerService.instance){ WindowManagerService.instance = new WindowManagerService(); }
|
||||
return WindowManagerService.instance;
|
||||
}
|
||||
|
||||
private constructor(){}
|
||||
|
||||
public openWindow(windowType: AppWindow): Promise<BrowserWindow>{
|
||||
const window = new BrowserWindow({...this.appWindowsOptions[windowType], ...this.baseWindowOption});
|
||||
const promise = window.loadURL(resolveHtmlPath(windowType));
|
||||
window.removeMenu();
|
||||
window.setMenu(null);
|
||||
|
||||
window.once("ready-to-show", () => {
|
||||
if (!window) { throw new Error('"window" is not defined'); }
|
||||
return window.show();
|
||||
});
|
||||
|
||||
window.once("closed", () => {
|
||||
this.windows.delete(windowType);
|
||||
if(!this.windows.size){ app.quit(); }
|
||||
});
|
||||
|
||||
this.windows.set(windowType, window);
|
||||
this.utilsService.setMainWindow(window);
|
||||
|
||||
return promise.then(() => window);
|
||||
}
|
||||
|
||||
public closeWindow(window: AppWindow){
|
||||
this.windows.get(window).close();
|
||||
}
|
||||
|
||||
public closeAllWindows(except?: AppWindow){
|
||||
this.windows.forEach((window, key) => {
|
||||
if(key === except){ return; }
|
||||
window.close();
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { BsManagerIcon } from "./components/nav-bar/bsmanager-icon.component";
|
||||
import { BsmProgressBar } from "./components/progress-bar/bsm-progress-bar.component";
|
||||
import TitleBar from "./components/title-bar/title-bar.component";
|
||||
import { useTranslation } from "./hooks/use-translation.hook";
|
||||
import { AutoUpdaterService } from "./services/auto-updater.service";
|
||||
import { ThemeService } from "./services/theme.service";
|
||||
import { WindowManagerService } from "./services/window-manager.service";
|
||||
|
||||
export default function Launcher() {
|
||||
|
||||
const themeService = ThemeService.getInstance();
|
||||
const updaterService = AutoUpdaterService.getInstance();
|
||||
const windowService = WindowManagerService.getInstance();
|
||||
|
||||
const constraintsRef = useRef(null);
|
||||
|
||||
const [text, setText] = useState("auto-update.checking");
|
||||
|
||||
const t = useTranslation();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const sub = themeService.theme$.subscribe(() => {
|
||||
if(themeService.isDark || (themeService.isOS && window.matchMedia('(prefers-color-scheme: dark)').matches)){ document.documentElement.classList.add('dark'); }
|
||||
else { document.documentElement.classList.remove('dark'); }
|
||||
});
|
||||
|
||||
updaterService.isUpdateAvailable().then(available => {
|
||||
if(!available){ return windowService.openThenCloseAll("index.html"); }
|
||||
setText("auto-update.downloading");
|
||||
updaterService.downloadUpdate().then(installed => installed && updaterService.quitAndInstall());
|
||||
});
|
||||
|
||||
return () => sub.unsubscribe();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full h-full">
|
||||
<TitleBar template="update"/>
|
||||
<div className="relative flex flex-col items-center justify-center pt-10">
|
||||
<motion.div ref={constraintsRef}>
|
||||
<motion.div drag dragConstraints={constraintsRef} animate={{rotate: [0, 10, 0]}} transition={{ duration: .6, repeat: Infinity, repeatDelay: 1.6 }}>
|
||||
<BsManagerIcon className={"w-52 cursor-pointer"}/>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
<span className="relative text-lg mt-16 mb-24 uppercase italic text-main-color-1 dark:text-gray-200">{t(text)}</span>
|
||||
<BsmProgressBar/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -10,9 +10,6 @@ export function AvailableVersionsSlide(props: {year: string}) {
|
||||
|
||||
const versionsService = BSVersionManagerService.getInstance();
|
||||
|
||||
console.log("*** AVAILABLE VERISON");
|
||||
console.log(availableVersions);
|
||||
|
||||
useEffect(() => {
|
||||
versionsService.availableVersions$.pipe(filter(versions => !!versions?.length), take(1)).subscribe(() => {
|
||||
setAvailableVersions(versionsService.getAvaibleVersionsOfYear(props.year));
|
||||
|
||||
@@ -17,7 +17,6 @@ export function AvailableVersionsSlider() {
|
||||
|
||||
useEffect(() => {
|
||||
versionManagerService.availableVersions$.pipe(filter(versions => !!versions?.length), take(1)).subscribe(() => {
|
||||
console.log("ouiiii");
|
||||
setAvailableYears(versionManagerService.getAvailableYears());
|
||||
});
|
||||
}, [])
|
||||
|
||||
@@ -21,7 +21,7 @@ export function EditVersionModal({resolver, clone = false}: {resolver: (x: Modal
|
||||
|
||||
const rename = () => {
|
||||
if(!name){ return; }
|
||||
resolver({exitCode: ModalExitCode.COMPLETED, data: {name, color}})
|
||||
resolver({exitCode: ModalExitCode.COMPLETED, data: {name: name.trim(), color}})
|
||||
}
|
||||
|
||||
const resetColor = () => {
|
||||
|
||||
@@ -1,24 +1,32 @@
|
||||
import { memo } from "react"
|
||||
import { useThemeColor } from "renderer/hooks/use-theme-color.hook";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
export const BsManagerIcon = memo(({className}: {className?: string}) => {
|
||||
|
||||
const {firstColor, secondColor} = useThemeColor();
|
||||
|
||||
export const BsManagerIcon = memo(({className, color1, color2}: {className: string, color1: string, color2: string}) => {
|
||||
return (
|
||||
<svg className={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
|
||||
<g fill={color1}>
|
||||
<path d="M626.75,485.91l20.82,351.94a35.21,35.21,0,0,1-15.49,31.36L487.37,965.35l-.06,0A35.56,35.56,0,0,1,476,970.12a34.85,34.85,0,0,1-23.51-2.87L136.58,809.9a115.45,115.45,0,0,1-63.75-96.49L52,361.46a35.26,35.26,0,0,1,15.23-31.21l145.05-96.36a35.72,35.72,0,0,1,11.27-4.7,34.87,34.87,0,0,1,23.51,2.87L563,389.42a115.41,115.41,0,0,1,63.75,96.49Z"/>
|
||||
<path filter="brightness(30%)" d="M613.78,486.67l20.82,352a22.34,22.34,0,0,1-32.26,21.31L286.4,702.57A102.43,102.43,0,0,1,229.83,617L209,265a22.35,22.35,0,0,1,32.26-21.32L557.2,401.05A102.42,102.42,0,0,1,613.78,486.67Z"/>
|
||||
</g>
|
||||
<g fill="#fff">
|
||||
<path d="M718.29,776.48,700,804.18c-40.63,39.5-87.06,67.25-133.81,90.75-87.32,43.9-203.67,77.19-249,90.34a48,48,0,0,1-26.17.16c-64-17.72-188.62-72-236.28-125.49a4.23,4.23,0,0,1,5.3-6.45c35.64,20.87,111.22,57.64,156.37,74.22,49.18,18.06,81.29,8.74,92.28-3.26a4.77,4.77,0,0,1,7.24.21c19.51,24,107.26,4.6,166.64-13C546.91,892.66,668.42,835.1,718.29,776.48Z"/>
|
||||
<path d="M522.09,933.81,374.64,989.49a3.92,3.92,0,0,0,1.44,7.58l54.62-.77a35.63,35.63,0,0,0,19-5.79l76-49.55A4,4,0,0,0,522.09,933.81Z"/>
|
||||
<path d="M218.92,195.56c-21.14.07-33.55,35.86-33.16,89.08.2,28,2.58,92.74,4.79,147.73.23,5.71-8.18,6.48-9,.81L143.13,162.47a4.38,4.38,0,0,1,7.12-4,63.63,63.63,0,0,0,21.93,11.85,4.61,4.61,0,0,0,5.9-3.72c4.2-27.7,16.63-58.74,37.35-88.74a4.36,4.36,0,0,1,7.56.69c10.86,23.87,49,103.8,93.34,152.79a4.65,4.65,0,0,1-5.62,7.22C274.14,219.18,227.7,195.54,218.92,195.56Z"/>
|
||||
<path d="M203.45,580.36a4.51,4.51,0,0,1-4.46-3.92L185.17,469.15A4.5,4.5,0,0,1,194.1,468l13.82,107.29a4.5,4.5,0,0,1-3.89,5A3.86,3.86,0,0,1,203.45,580.36Z"/>
|
||||
<path d="M577.08,54.58c-46.79,15.85-115.45,40.56-158.73,62.79a35.5,35.5,0,0,0-18.57,24.53c-3.95,19.49-11,56.09-19,107.26-.7,4.48-7.36,3.78-7.11-.75L384.33,53.68a3.78,3.78,0,0,1,7.46-.66l3.49,14.85a2.57,2.57,0,0,0,4.69.77c6.18-10,22.37-32.79,57.32-65a4.13,4.13,0,0,1,6.56,4.72L431.31,81.25s78.78-19.37,144-33.09C579.42,47.29,581,53.24,577.08,54.58Z"/>
|
||||
</g>
|
||||
<g fill={color2}>
|
||||
<path filter="brightness(60%) saturate(120%)" d="M947.07,410.35,889.32,758.14a35.18,35.18,0,0,1-22.06,27.15L704.83,846.94l-.06,0a35.52,35.52,0,0,1-12.06,2.11,34.83,34.83,0,0,1-22.29-8L397.25,617.55a115.43,115.43,0,0,1-40.76-108.22l57.75-347.8A35.25,35.25,0,0,1,436,134.47L598.83,72.68a35.51,35.51,0,0,1,12-2.08,34.83,34.83,0,0,1,22.29,8L906.31,302.12a115.38,115.38,0,0,1,40.76,108.23Z"/>
|
||||
<path d="M934.25,408.22,876.5,756a22.34,22.34,0,0,1-36.18,13.63L567.15,546.13a102.42,102.42,0,0,1-36.17-96L588.73,102.3a22.34,22.34,0,0,1,36.18-13.63L898.08,312.18A102.42,102.42,0,0,1,934.25,408.22Z"/>
|
||||
</g>
|
||||
<ellipse fill="#fff" cx="732.61" cy="429.16" rx="62.83" ry="110.73" transform="translate(-87.86 210.7) rotate(-15.45)"/>
|
||||
</svg>
|
||||
<motion.div className="cursor-pointer" whileTap={{rotate: -10}}>
|
||||
<svg className={className} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000">
|
||||
<g fill={firstColor}>
|
||||
<path d="M626.75,485.91l20.82,351.94a35.21,35.21,0,0,1-15.49,31.36L487.37,965.35l-.06,0A35.56,35.56,0,0,1,476,970.12a34.85,34.85,0,0,1-23.51-2.87L136.58,809.9a115.45,115.45,0,0,1-63.75-96.49L52,361.46a35.26,35.26,0,0,1,15.23-31.21l145.05-96.36a35.72,35.72,0,0,1,11.27-4.7,34.87,34.87,0,0,1,23.51,2.87L563,389.42a115.41,115.41,0,0,1,63.75,96.49Z"/>
|
||||
<path filter="brightness(30%)" d="M613.78,486.67l20.82,352a22.34,22.34,0,0,1-32.26,21.31L286.4,702.57A102.43,102.43,0,0,1,229.83,617L209,265a22.35,22.35,0,0,1,32.26-21.32L557.2,401.05A102.42,102.42,0,0,1,613.78,486.67Z"/>
|
||||
</g>
|
||||
<g fill="#fff">
|
||||
<path d="M718.29,776.48,700,804.18c-40.63,39.5-87.06,67.25-133.81,90.75-87.32,43.9-203.67,77.19-249,90.34a48,48,0,0,1-26.17.16c-64-17.72-188.62-72-236.28-125.49a4.23,4.23,0,0,1,5.3-6.45c35.64,20.87,111.22,57.64,156.37,74.22,49.18,18.06,81.29,8.74,92.28-3.26a4.77,4.77,0,0,1,7.24.21c19.51,24,107.26,4.6,166.64-13C546.91,892.66,668.42,835.1,718.29,776.48Z"/>
|
||||
<path d="M522.09,933.81,374.64,989.49a3.92,3.92,0,0,0,1.44,7.58l54.62-.77a35.63,35.63,0,0,0,19-5.79l76-49.55A4,4,0,0,0,522.09,933.81Z"/>
|
||||
<path d="M218.92,195.56c-21.14.07-33.55,35.86-33.16,89.08.2,28,2.58,92.74,4.79,147.73.23,5.71-8.18,6.48-9,.81L143.13,162.47a4.38,4.38,0,0,1,7.12-4,63.63,63.63,0,0,0,21.93,11.85,4.61,4.61,0,0,0,5.9-3.72c4.2-27.7,16.63-58.74,37.35-88.74a4.36,4.36,0,0,1,7.56.69c10.86,23.87,49,103.8,93.34,152.79a4.65,4.65,0,0,1-5.62,7.22C274.14,219.18,227.7,195.54,218.92,195.56Z"/>
|
||||
<path d="M203.45,580.36a4.51,4.51,0,0,1-4.46-3.92L185.17,469.15A4.5,4.5,0,0,1,194.1,468l13.82,107.29a4.5,4.5,0,0,1-3.89,5A3.86,3.86,0,0,1,203.45,580.36Z"/>
|
||||
<path d="M577.08,54.58c-46.79,15.85-115.45,40.56-158.73,62.79a35.5,35.5,0,0,0-18.57,24.53c-3.95,19.49-11,56.09-19,107.26-.7,4.48-7.36,3.78-7.11-.75L384.33,53.68a3.78,3.78,0,0,1,7.46-.66l3.49,14.85a2.57,2.57,0,0,0,4.69.77c6.18-10,22.37-32.79,57.32-65a4.13,4.13,0,0,1,6.56,4.72L431.31,81.25s78.78-19.37,144-33.09C579.42,47.29,581,53.24,577.08,54.58Z"/>
|
||||
</g>
|
||||
<g fill={secondColor}>
|
||||
<path filter="brightness(60%) saturate(120%)" d="M947.07,410.35,889.32,758.14a35.18,35.18,0,0,1-22.06,27.15L704.83,846.94l-.06,0a35.52,35.52,0,0,1-12.06,2.11,34.83,34.83,0,0,1-22.29-8L397.25,617.55a115.43,115.43,0,0,1-40.76-108.22l57.75-347.8A35.25,35.25,0,0,1,436,134.47L598.83,72.68a35.51,35.51,0,0,1,12-2.08,34.83,34.83,0,0,1,22.29,8L906.31,302.12a115.38,115.38,0,0,1,40.76,108.23Z"/>
|
||||
<path d="M934.25,408.22,876.5,756a22.34,22.34,0,0,1-36.18,13.63L567.15,546.13a102.42,102.42,0,0,1-36.17-96L588.73,102.3a22.34,22.34,0,0,1,36.18-13.63L898.08,312.18A102.42,102.42,0,0,1,934.25,408.22Z"/>
|
||||
</g>
|
||||
<ellipse fill="#fff" cx="732.61" cy="429.16" rx="62.83" ry="110.73" transform="translate(-87.86 210.7) rotate(-15.45)"/>
|
||||
</svg>
|
||||
</motion.div>
|
||||
|
||||
)
|
||||
})
|
||||
|
||||
@@ -4,7 +4,6 @@ import { BSVersionManagerService } from '../../services/bs-version-manager.servi
|
||||
import { Link } from 'react-router-dom';
|
||||
import { BsmIcon } from '../svgs/bsm-icon.component';
|
||||
import { useObservable } from 'renderer/hooks/use-observable.hook';
|
||||
import { useThemeColor } from 'renderer/hooks/use-theme-color.hook';
|
||||
import { BsManagerIcon } from './bsmanager-icon.component';
|
||||
|
||||
export function NavBar() {
|
||||
@@ -12,12 +11,11 @@ export function NavBar() {
|
||||
const bsVersionServoce = BSVersionManagerService.getInstance();
|
||||
|
||||
const installedVersions = useObservable(bsVersionServoce.installedVersions$);
|
||||
const {firstColor, secondColor} = useThemeColor();
|
||||
|
||||
return (
|
||||
<div id='nav-bar' className='z-10 flex flex-col h-full max-h-full items-center p-1 bg-light-main-color-1 dark:bg-main-color-1'>
|
||||
<div className='w-full flex items-start content-start justify-center relative mb-3'>
|
||||
<BsManagerIcon className='relative aspect-square w-16 h-16' color1={firstColor} color2={secondColor}/>
|
||||
<BsManagerIcon className='relative aspect-square w-16 h-16'/>
|
||||
</div>
|
||||
<div id='versions' className='w-fit max-w-[120px] relative left-[2px] grow overflow-y-hidden scrollbar-track-transparent scrollbar-thin scrollbar-thumb-neutral-900 hover:overflow-y-scroll'>
|
||||
{installedVersions && installedVersions.map((version) => <BsVersionItem key={JSON.stringify(version)} version={version}/>)}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
||||
import { IpcService } from 'renderer/services/ipc.service';
|
||||
import './title-bar.component.css'
|
||||
|
||||
export default function TitleBar() {
|
||||
export default function TitleBar({template = "main"} : {template?: "update"|"main"}) {
|
||||
|
||||
const ipcService = IpcService.getInstance();
|
||||
|
||||
@@ -31,23 +31,23 @@ export default function TitleBar() {
|
||||
}
|
||||
|
||||
return (
|
||||
<header id="titlebar" className="min-h-[22px] bg-light-main-color-1 dark:bg-main-color-1 w-screen h-10 flex content-center items-center justify-start z-10">
|
||||
<div id="drag-region" className='grow basis-0'>
|
||||
<div id="window-title" className='pl-1'>
|
||||
<span className='text-gray-800 dark:text-gray-100 font-bold text-xs italic'>BSManager</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="window-controls" className=''>
|
||||
<header id="titlebar" className="min-h-[22px] bg-light-main-color-1 dark:bg-main-color-1 w-screen h-[22px] flex content-center items-center justify-start z-10">
|
||||
<div id="drag-region" className='grow basis-0 h-full'>
|
||||
{template !== "update" && (<div id="window-title" className='pl-1'>
|
||||
<span className='text-gray-800 dark:text-gray-100 font-bold text-xs italic'>BSManager</span>
|
||||
</div>)}
|
||||
</div>
|
||||
{template !== "update" && (<div id="window-controls">
|
||||
<div onClick={minimizeWindow} className="button button text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-[#4F545C] cursor-pointer" id="min-button" >
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect fill="currentColor" width="10" height="1" x="1" y="6"> </rect></svg>
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect fill="currentColor" width="10" height="1" x="1" y="6"> </rect></svg>
|
||||
</div>
|
||||
<div onClick={toogleMaximize} className="button text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-[#4F545C] cursor-pointer" id="max-button">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="currentColor"> </rect></svg>
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="currentColor"> </rect></svg>
|
||||
</div>
|
||||
<div onClick={closeWindow} className="button text-gray-800 dark:text-gray-200 cursor-pointer" id="close-button" draggable="false">
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><polygon fill="currentColor" fillRule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"> </polygon></svg>
|
||||
<svg aria-hidden="false" width="12" height="12" viewBox="0 0 12 12"><polygon fill="currentColor" fillRule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"> </polygon></svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>)}
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
+14
-7
@@ -1,14 +1,21 @@
|
||||
//@ts-ignore
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { HashRouter } from 'react-router-dom';
|
||||
import App from './App';
|
||||
import Launcher from './Launcher';
|
||||
import 'tailwindcss/tailwind.css';
|
||||
import './index.css'
|
||||
|
||||
const container = document.getElementById('root')!;
|
||||
const root = createRoot(container);
|
||||
const launcherContainer = document.getElementById('launcher');
|
||||
|
||||
root.render(
|
||||
<HashRouter>
|
||||
<App />
|
||||
</HashRouter>
|
||||
);
|
||||
if(!!launcherContainer){
|
||||
createRoot(launcherContainer).render(<Launcher/>)
|
||||
}
|
||||
else{
|
||||
const root = document.getElementById('root');
|
||||
createRoot(root).render(
|
||||
<HashRouter>
|
||||
<App />
|
||||
</HashRouter>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://use.typekit.net/okr8ven.css">
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="script-src 'self' 'unsafe-inline'"
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="launcher"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -78,7 +78,6 @@ export function VersionViewer() {
|
||||
const newVersionPage = bsVersionManagerService.getInstalledVersions()[0];
|
||||
navigateToVersion(newVersionPage);
|
||||
})
|
||||
.catch((e) => {console.log("*** ", e)})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Observable } from "rxjs";
|
||||
import { map } from "rxjs/operators";
|
||||
import { IpcService } from "./ipc.service";
|
||||
import { ProgressBarService } from "./progress-bar.service";
|
||||
|
||||
export class AutoUpdaterService{
|
||||
|
||||
private static instance: AutoUpdaterService;
|
||||
|
||||
private progressService: ProgressBarService;
|
||||
private ipcService: IpcService;
|
||||
|
||||
private downloadProgress$: Observable<number>;
|
||||
|
||||
public static getInstance(): AutoUpdaterService{
|
||||
if(!AutoUpdaterService.instance){ AutoUpdaterService.instance = new AutoUpdaterService(); }
|
||||
return AutoUpdaterService.instance;
|
||||
}
|
||||
|
||||
private constructor(){
|
||||
this.progressService = ProgressBarService.getInstance();
|
||||
this.ipcService = IpcService.getInstance();
|
||||
|
||||
this.downloadProgress$ = this.ipcService.watch<number>("update-download-progress").pipe(map(res => res.success ? res.data : 0));
|
||||
}
|
||||
|
||||
public isUpdateAvailable(): Promise<boolean>{
|
||||
return this.ipcService.send<boolean>("check-update").then(res => {
|
||||
if(!res.success){ return false; }
|
||||
return res.data;
|
||||
})
|
||||
}
|
||||
|
||||
public downloadUpdate(): Promise<boolean>{
|
||||
const promise = this.ipcService.send<boolean>("download-update").then(res => {
|
||||
return res.success;
|
||||
});
|
||||
|
||||
this.progressService.show(this.downloadProgress$, true);
|
||||
return promise;
|
||||
}
|
||||
|
||||
public quitAndInstall(){
|
||||
this.ipcService.sendLazy("install-update");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -113,8 +113,8 @@ export class BsDownloaderService{
|
||||
|
||||
this.progressBarService.hide(true);
|
||||
this.resetDownload();
|
||||
if(res.success){ this.notificationService.notifySuccess({title: `notifications.bs-download.success.titles.${isVerification ? "verification-finished" : "download-success"}`, duration: 3000}); }
|
||||
else if(res.data){ this.notificationService.notifyError({title: `notifications.bs-download.errors.titles.${res.data}`, duration: 3000}); }
|
||||
if(res.success && isFirstCall){ this.notificationService.notifySuccess({title: `notifications.bs-download.success.titles.${isVerification ? "verification-finished" : "download-success"}`, duration: 3000}); }
|
||||
else if(res.data && isFirstCall){ console.log("aaaa"); this.notificationService.notifyError({title: `notifications.types.error`, desc: `notifications.bs-download.errors.msg.${res.data}`, duration: 3000}); }
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export class I18nService {
|
||||
public translate(translationKey: string, args?: Record<string, string>): string{
|
||||
let translated = this.cache.get(translationKey);
|
||||
if(!translated){
|
||||
console.log(translationKey);
|
||||
translated = getProperty(this.dictionary, translationKey);
|
||||
translated ? this.cache.set(translated, translationKey) : translated = translationKey;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export class IpcService {
|
||||
return promise;
|
||||
}
|
||||
|
||||
public sendLazy(channel: string, request?: IpcRequest<any>): void{
|
||||
public sendLazy<T = any>(channel: string, request?: IpcRequest<T>): void{
|
||||
window.electron.ipcRenderer.sendMessage(channel, request);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { AppWindow } from "shared/models/window-manager/app-window.model";
|
||||
import { IpcService } from "./ipc.service";
|
||||
|
||||
export class WindowManagerService{
|
||||
|
||||
private static instance: WindowManagerService;
|
||||
|
||||
private readonly ipcService: IpcService;
|
||||
|
||||
public static getInstance(): WindowManagerService{
|
||||
if(!WindowManagerService.instance){ WindowManagerService.instance = new WindowManagerService(); }
|
||||
return WindowManagerService.instance;
|
||||
}
|
||||
|
||||
private constructor(){
|
||||
this.ipcService = IpcService.getInstance();
|
||||
}
|
||||
|
||||
public openThenCloseAll(window: AppWindow){
|
||||
this.ipcService.sendLazy<AppWindow>("open-window-then-close-all", {args: window});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export type AppWindow = "index.html" | "launcher.html";
|
||||
Reference in New Issue
Block a user