mirror of
https://github.com/WowUp/WowUp.git
synced 2026-05-19 03:54:44 -04:00
All new app update flow
Fix an issue with scanning and multi toc
This commit is contained in:
@@ -1,83 +1,177 @@
|
||||
import { app, BrowserWindow, ipcMain } from "electron";
|
||||
import * as log from "electron-log";
|
||||
import { autoUpdater, UpdateCheckResult } from "electron-updater";
|
||||
import {
|
||||
APP_UPDATE_AVAILABLE,
|
||||
APP_UPDATE_CHECK_END,
|
||||
APP_UPDATE_CHECK_FOR_UPDATE,
|
||||
APP_UPDATE_CHECK_START,
|
||||
APP_UPDATE_DOWNLOADED,
|
||||
APP_UPDATE_ERROR,
|
||||
APP_UPDATE_INSTALL,
|
||||
APP_UPDATE_NOT_AVAILABLE,
|
||||
APP_UPDATE_START_DOWNLOAD,
|
||||
} from "../src/common/constants";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import { IPC_APP_CHECK_UPDATE, IPC_APP_INSTALL_UPDATE, IPC_APP_UPDATE_STATE } from "../src/common/constants";
|
||||
import { AppUpdateDownloadProgress, AppUpdateEvent, AppUpdateState } from "../src/common/wowup/models";
|
||||
|
||||
export const checkForUpdates = async (win: BrowserWindow): Promise<UpdateCheckResult> => {
|
||||
let result = null;
|
||||
export class AppUpdater {
|
||||
private _win: BrowserWindow;
|
||||
|
||||
try {
|
||||
win.webContents.send(APP_UPDATE_CHECK_START);
|
||||
result = await autoUpdater.checkForUpdates();
|
||||
} finally {
|
||||
win.webContents.send(APP_UPDATE_CHECK_END);
|
||||
public constructor(win: BrowserWindow) {
|
||||
this._win = win;
|
||||
this.initUpdater();
|
||||
this.initIpcHandlers();
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
public dispose(): void {}
|
||||
|
||||
public async checkForUpdates(): Promise<void> {
|
||||
try {
|
||||
const result = await autoUpdater.checkForUpdates();
|
||||
log.info(`checkForUpdates`, result);
|
||||
} catch (e) {
|
||||
log.error("checkForUpdates", e);
|
||||
}
|
||||
}
|
||||
|
||||
private initIpcHandlers() {
|
||||
ipcMain.on(IPC_APP_CHECK_UPDATE, () => {
|
||||
this.checkForUpdates().catch((e) => console.error(e));
|
||||
});
|
||||
|
||||
// Used this solution for Mac support
|
||||
// https://github.com/electron-userland/electron-builder/issues/1604#issuecomment-372091881
|
||||
ipcMain.on(IPC_APP_INSTALL_UPDATE, () => {
|
||||
app.removeAllListeners("window-all-closed");
|
||||
const browserWindows = BrowserWindow.getAllWindows();
|
||||
browserWindows.forEach(function (browserWindow) {
|
||||
browserWindow.removeAllListeners("close");
|
||||
});
|
||||
autoUpdater.quitAndInstall();
|
||||
});
|
||||
}
|
||||
|
||||
private initUpdater() {
|
||||
autoUpdater.logger = log;
|
||||
autoUpdater.autoDownload = true;
|
||||
|
||||
autoUpdater.on("checking-for-update", () => {
|
||||
log.info("autoUpdater checking-for-update");
|
||||
const evt: AppUpdateEvent = {
|
||||
state: AppUpdateState.CheckingForUpdate,
|
||||
};
|
||||
|
||||
this._win?.webContents?.send(IPC_APP_UPDATE_STATE, evt);
|
||||
});
|
||||
|
||||
autoUpdater.on("update-available", () => {
|
||||
log.info("autoUpdater update-available");
|
||||
const evt: AppUpdateEvent = {
|
||||
state: AppUpdateState.UpdateAvailable,
|
||||
};
|
||||
|
||||
this._win?.webContents?.send(IPC_APP_UPDATE_STATE, evt);
|
||||
});
|
||||
|
||||
autoUpdater.on("update-not-available", () => {
|
||||
log.info("autoUpdater update-not-available");
|
||||
const evt: AppUpdateEvent = {
|
||||
state: AppUpdateState.UpdateNotAvailable,
|
||||
};
|
||||
|
||||
this._win?.webContents?.send(IPC_APP_UPDATE_STATE, evt);
|
||||
});
|
||||
|
||||
autoUpdater.on("download-progress", (progressObj: AppUpdateDownloadProgress) => {
|
||||
const evt: AppUpdateEvent = {
|
||||
state: AppUpdateState.Downloading,
|
||||
progress: { ...progressObj },
|
||||
};
|
||||
|
||||
this._win?.webContents?.send(IPC_APP_UPDATE_STATE, evt);
|
||||
});
|
||||
|
||||
autoUpdater.on("update-downloaded", () => {
|
||||
log.info("autoUpdater update-downloaded");
|
||||
const evt: AppUpdateEvent = {
|
||||
state: AppUpdateState.Downloaded,
|
||||
};
|
||||
|
||||
this._win?.webContents?.send(IPC_APP_UPDATE_STATE, evt);
|
||||
});
|
||||
|
||||
autoUpdater.on("error", (e) => {
|
||||
log.error("autoUpdater error", e);
|
||||
const evt: AppUpdateEvent = {
|
||||
state: AppUpdateState.Error,
|
||||
error: e.toString(),
|
||||
};
|
||||
|
||||
this._win?.webContents?.send(IPC_APP_UPDATE_STATE, evt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// export const checkForUpdates = async (win: BrowserWindow): Promise<UpdateCheckResult> => {
|
||||
// let result = undefined;
|
||||
// try {
|
||||
// win.webContents.send(APP_UPDATE_CHECK_START);
|
||||
// result = await autoUpdater.checkForUpdates();
|
||||
// } catch (e) {
|
||||
// console.error(e);
|
||||
// } finally {
|
||||
// win.webContents.send(APP_UPDATE_CHECK_END);
|
||||
// }
|
||||
|
||||
// return result;
|
||||
// };
|
||||
|
||||
// Example: https://github.com/electron-userland/electron-builder/blob/docs/encapsulated%20manual%20update%20via%20menu.js
|
||||
export function initializeAppUpdater(win: BrowserWindow): void {
|
||||
autoUpdater.logger = log;
|
||||
autoUpdater.autoDownload = true;
|
||||
// autoUpdater.allowPrerelease = true;
|
||||
// export function initializeAppUpdater(win: BrowserWindow): void {
|
||||
// autoUpdater.logger = log;
|
||||
// autoUpdater.autoDownload = true;
|
||||
// // autoUpdater.allowPrerelease = true;
|
||||
|
||||
autoUpdater.on("update-available", () => {
|
||||
log.info(APP_UPDATE_AVAILABLE);
|
||||
win.webContents.send(APP_UPDATE_AVAILABLE);
|
||||
});
|
||||
// autoUpdater.on("update-available", () => {
|
||||
// log.info(APP_UPDATE_AVAILABLE);
|
||||
// win.webContents.send(APP_UPDATE_AVAILABLE);
|
||||
// });
|
||||
|
||||
autoUpdater.on("update-not-available", () => {
|
||||
log.info(APP_UPDATE_AVAILABLE);
|
||||
win.webContents.send(APP_UPDATE_NOT_AVAILABLE);
|
||||
});
|
||||
// autoUpdater.on("update-not-available", () => {
|
||||
// log.info(APP_UPDATE_AVAILABLE);
|
||||
// win.webContents.send(APP_UPDATE_NOT_AVAILABLE);
|
||||
// });
|
||||
|
||||
autoUpdater.on("update-downloaded", () => {
|
||||
log.info(APP_UPDATE_DOWNLOADED);
|
||||
win.webContents.send(APP_UPDATE_DOWNLOADED);
|
||||
});
|
||||
// autoUpdater.on("update-downloaded", () => {
|
||||
// log.info(APP_UPDATE_DOWNLOADED);
|
||||
// win.webContents.send(APP_UPDATE_DOWNLOADED);
|
||||
// });
|
||||
|
||||
autoUpdater.on("error", (e) => {
|
||||
if (e.message.indexOf("dev-app-update.yml") !== -1) {
|
||||
return;
|
||||
}
|
||||
// autoUpdater.on("error", (e) => {
|
||||
// if (e.message.indexOf("dev-app-update.yml") !== -1) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
log.error(APP_UPDATE_ERROR, e);
|
||||
win.webContents.send(APP_UPDATE_ERROR, e);
|
||||
});
|
||||
}
|
||||
// log.error(APP_UPDATE_ERROR, e);
|
||||
// win.webContents.send(APP_UPDATE_ERROR, e);
|
||||
// });
|
||||
// }
|
||||
|
||||
export function initializeAppUpdateIpcHandlers(win: BrowserWindow): void {
|
||||
ipcMain.handle(APP_UPDATE_START_DOWNLOAD, async () => {
|
||||
log.info(APP_UPDATE_START_DOWNLOAD);
|
||||
win.webContents.send(APP_UPDATE_START_DOWNLOAD);
|
||||
return await autoUpdater.downloadUpdate();
|
||||
});
|
||||
// export function initializeAppUpdateIpcHandlers(win: BrowserWindow): void {
|
||||
// ipcMain.handle(APP_UPDATE_START_DOWNLOAD, async () => {
|
||||
// log.info(APP_UPDATE_START_DOWNLOAD);
|
||||
// win.webContents.send(APP_UPDATE_START_DOWNLOAD);
|
||||
// return await autoUpdater.downloadUpdate();
|
||||
// });
|
||||
|
||||
// Used this solution for Mac support
|
||||
// https://github.com/electron-userland/electron-builder/issues/1604#issuecomment-372091881
|
||||
ipcMain.handle(APP_UPDATE_INSTALL, () => {
|
||||
log.info(APP_UPDATE_INSTALL);
|
||||
app.removeAllListeners("window-all-closed");
|
||||
const browserWindows = BrowserWindow.getAllWindows();
|
||||
browserWindows.forEach(function (browserWindow) {
|
||||
browserWindow.removeAllListeners("close");
|
||||
});
|
||||
autoUpdater.quitAndInstall();
|
||||
});
|
||||
// // Used this solution for Mac support
|
||||
// // https://github.com/electron-userland/electron-builder/issues/1604#issuecomment-372091881
|
||||
// ipcMain.handle(APP_UPDATE_INSTALL, () => {
|
||||
// log.info(APP_UPDATE_INSTALL);
|
||||
// app.removeAllListeners("window-all-closed");
|
||||
// const browserWindows = BrowserWindow.getAllWindows();
|
||||
// browserWindows.forEach(function (browserWindow) {
|
||||
// browserWindow.removeAllListeners("close");
|
||||
// });
|
||||
// autoUpdater.quitAndInstall();
|
||||
// });
|
||||
|
||||
ipcMain.handle(APP_UPDATE_CHECK_FOR_UPDATE, async () => {
|
||||
log.info(APP_UPDATE_CHECK_FOR_UPDATE);
|
||||
return await checkForUpdates(win);
|
||||
});
|
||||
}
|
||||
// ipcMain.handle(APP_UPDATE_CHECK_FOR_UPDATE, async () => {
|
||||
// log.info(APP_UPDATE_CHECK_FOR_UPDATE);
|
||||
// try {
|
||||
// return await checkForUpdates(win);
|
||||
// } catch (e) {
|
||||
// console.error(e);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
@@ -4,11 +4,11 @@ import { find } from "lodash";
|
||||
import * as minimist from "minimist";
|
||||
import { arch as osArch, release as osRelease, type as osType } from "os";
|
||||
import { join } from "path";
|
||||
import { format as urlFormat, pathToFileURL } from "url";
|
||||
import { pathToFileURL } from "url";
|
||||
import { inspect } from "util";
|
||||
|
||||
import { createAppMenu } from "./app-menu";
|
||||
import { initializeAppUpdateIpcHandlers, initializeAppUpdater } from "./app-updater";
|
||||
import { AppUpdater } from "./app-updater";
|
||||
import { initializeIpcHandlers, setPendingOpenUrl } from "./ipc-events";
|
||||
import * as platform from "./platform";
|
||||
import {
|
||||
@@ -74,6 +74,7 @@ log.info("USER_AGENT", USER_AGENT);
|
||||
|
||||
let appIsQuitting = false;
|
||||
let win: BrowserWindow = null;
|
||||
let appUpdater: AppUpdater | undefined = undefined;
|
||||
let loadFailCount = 0;
|
||||
|
||||
// APP MENU SETUP
|
||||
@@ -156,6 +157,7 @@ if (app.isReady()) {
|
||||
app.on("before-quit", () => {
|
||||
win = null;
|
||||
appIsQuitting = true;
|
||||
appUpdater?.dispose();
|
||||
});
|
||||
|
||||
// Quit when all windows are closed.
|
||||
@@ -265,10 +267,10 @@ function createWindow(): BrowserWindow {
|
||||
// Create the browser window.
|
||||
win = new BrowserWindow(windowOptions);
|
||||
|
||||
appUpdater = new AppUpdater(win);
|
||||
|
||||
initializeIpcHandlers(win, USER_AGENT);
|
||||
initializeStoreIpcHandlers();
|
||||
initializeAppUpdater(win);
|
||||
initializeAppUpdateIpcHandlers(win);
|
||||
|
||||
// Keep track of window state
|
||||
mainWindowManager.monitorState(win);
|
||||
@@ -329,6 +331,8 @@ function createWindow(): BrowserWindow {
|
||||
} else if (mainWindowManager.isMaximized) {
|
||||
win.maximize();
|
||||
}
|
||||
|
||||
appUpdater.checkForUpdates().catch((e) => console.error(e));
|
||||
});
|
||||
|
||||
win.on("close", (e) => {
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
],
|
||||
"win": {
|
||||
"icon": "electron-build/icon.ico",
|
||||
"target": ["portable"],
|
||||
"target": ["nsis"],
|
||||
"forceCodeSigning": false,
|
||||
"publisherName": "WowUp LLC"
|
||||
},
|
||||
|
||||
11
wowup-electron/package-lock.json
generated
11
wowup-electron/package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wowup",
|
||||
"version": "2.4.0-beta.1",
|
||||
"version": "2.4.0-beta.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -11441,7 +11441,8 @@
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
|
||||
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
@@ -13590,7 +13591,8 @@
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.8",
|
||||
"resolved": "",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
|
||||
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
@@ -14495,7 +14497,8 @@
|
||||
},
|
||||
"normalize-url": {
|
||||
"version": "4.5.0",
|
||||
"resolved": "",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
|
||||
"integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
|
||||
"dev": true
|
||||
},
|
||||
"npm-bundled": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "wowup",
|
||||
"productName": "WowUp",
|
||||
"version": "2.4.0-beta.2",
|
||||
"version": "2.4.0-beta.1",
|
||||
"description": "World of Warcraft addon updater",
|
||||
"homepage": "https://wowup.io",
|
||||
"author": {
|
||||
|
||||
@@ -43,6 +43,7 @@ import * as AddonUtils from "../utils/addon.utils";
|
||||
import { getEnumName } from "../utils/enum.utils";
|
||||
import { AddonProvider, GetAllResult } from "./addon-provider";
|
||||
import { strictFilter } from "../utils/array.utils";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
|
||||
interface ProtocolData {
|
||||
addonId: number;
|
||||
@@ -84,6 +85,7 @@ export class CurseAddonProvider extends AddonProvider {
|
||||
private _cachingService: CachingService,
|
||||
private _electronService: ElectronService,
|
||||
private _wowupApiService: WowUpApiService,
|
||||
private _tocService: TocService,
|
||||
_networkService: NetworkService
|
||||
) {
|
||||
super();
|
||||
@@ -817,7 +819,8 @@ export class CurseAddonProvider extends AddonProvider {
|
||||
|
||||
const latestFiles = this.getLatestFiles(scanResult.searchResult, installation.clientType);
|
||||
|
||||
const gameVersion = AddonUtils.getGameVersion(scanResult.addonFolder?.toc.interface);
|
||||
const targetToc = this._tocService.getTocForGameType2(scanResult.addonFolder.tocs, installation.clientType);
|
||||
const gameVersion = AddonUtils.getGameVersion(targetToc.interface);
|
||||
|
||||
let channelType = this.getChannelType(scanResult.exactMatch.file.releaseType);
|
||||
let latestVersion = latestFiles.find((lf) => this.getChannelType(lf.releaseType) <= channelType);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { AddonFolder } from "../models/wowup/addon-folder";
|
||||
import { getEnumName } from "../utils/enum.utils";
|
||||
import { AddonProvider } from "./addon-provider";
|
||||
import { getGameVersion } from "../utils/addon.utils";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
|
||||
export class RaiderIoAddonProvider extends AddonProvider {
|
||||
private readonly _scanWebsite = "https://raider.io";
|
||||
@@ -21,7 +22,7 @@ export class RaiderIoAddonProvider extends AddonProvider {
|
||||
public readonly allowEdit = false;
|
||||
public enabled = true;
|
||||
|
||||
public constructor() {
|
||||
public constructor(private _tocService: TocService) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -36,6 +37,7 @@ export class RaiderIoAddonProvider extends AddonProvider {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
const targetToc = this._tocService.getTocForGameType2(raiderIo.tocs, installation.clientType);
|
||||
const dependencies = _.filter(addonFolders, (addonFolder) => this.isRaiderIoDependant(addonFolder));
|
||||
console.debug("RAIDER IO CLIENT FOUND", dependencies);
|
||||
|
||||
@@ -44,31 +46,33 @@ export class RaiderIoAddonProvider extends AddonProvider {
|
||||
const installedFolders = installedFolderList.join(",");
|
||||
|
||||
for (const rioAddonFolder of rioAddonFolders) {
|
||||
const subTargetToc = this._tocService.getTocForGameType2(rioAddonFolder.tocs, installation.clientType);
|
||||
|
||||
rioAddonFolder.matchingAddon = {
|
||||
autoUpdateEnabled: false,
|
||||
channelType: AddonChannelType.Stable,
|
||||
clientType: installation.clientType,
|
||||
id: uuidv4(),
|
||||
isIgnored: true,
|
||||
name: raiderIo.toc.title ?? "unknown",
|
||||
author: rioAddonFolder.toc.author,
|
||||
name: targetToc.title ?? "unknown",
|
||||
author: subTargetToc.author,
|
||||
downloadUrl: "",
|
||||
externalId: this.name,
|
||||
externalUrl: this._scanWebsite,
|
||||
gameVersion: getGameVersion(rioAddonFolder.toc.interface),
|
||||
gameVersion: getGameVersion(subTargetToc.interface),
|
||||
installedAt: new Date(),
|
||||
installedFolders: installedFolders,
|
||||
installedFolderList: installedFolderList,
|
||||
installedVersion: rioAddonFolder.toc.version || raiderIo.toc.version,
|
||||
latestVersion: raiderIo.toc.version,
|
||||
installedVersion: subTargetToc.version || targetToc.version,
|
||||
latestVersion: subTargetToc.version,
|
||||
providerName: this.name,
|
||||
thumbnailUrl: "http://cdnassets.raider.io/images/fb_app_image.jpg?2019-11-18",
|
||||
updatedAt: new Date(),
|
||||
summary: rioAddonFolder.toc.notes,
|
||||
summary: subTargetToc.notes,
|
||||
downloadCount: 0,
|
||||
screenshotUrls: [],
|
||||
releasedAt: new Date(),
|
||||
isLoadOnDemand: rioAddonFolder.toc.loadOnDemand === "1",
|
||||
isLoadOnDemand: subTargetToc.loadOnDemand === "1",
|
||||
externalChannel: getEnumName(AddonChannelType, AddonChannelType.Stable),
|
||||
installationId: installation.id,
|
||||
};
|
||||
@@ -80,14 +84,13 @@ export class RaiderIoAddonProvider extends AddonProvider {
|
||||
private isRaiderIo(addonFolder: AddonFolder) {
|
||||
return (
|
||||
addonFolder.name === this._scanFolderName &&
|
||||
addonFolder.toc?.website === this._scanWebsite &&
|
||||
addonFolder.toc?.addonProvider === this._scanAddonProvider
|
||||
addonFolder.tocs.some((toc) => toc.website === this._scanWebsite && toc.addonProvider === this._scanAddonProvider)
|
||||
);
|
||||
}
|
||||
|
||||
private isRaiderIoDependant(addonFolder: AddonFolder) {
|
||||
return (
|
||||
addonFolder.toc?.dependencies !== undefined && addonFolder.toc.dependencies.indexOf(this._scanFolderName) !== -1
|
||||
return addonFolder.tocs.some(
|
||||
(toc) => toc.dependencies !== undefined && toc.dependencies.indexOf(this._scanFolderName) !== -1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import { CircuitBreakerWrapper, NetworkService } from "../services/network/netwo
|
||||
import { getGameVersion } from "../utils/addon.utils";
|
||||
import { getEnumName } from "../utils/enum.utils";
|
||||
import { AddonProvider, GetAllResult } from "./addon-provider";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
|
||||
const API_URL = "https://www.tukui.org/api.php";
|
||||
const CLIENT_API_URL = "https://www.tukui.org/client-api.php";
|
||||
@@ -34,7 +35,11 @@ export class TukUiAddonProvider extends AddonProvider {
|
||||
|
||||
public enabled = true;
|
||||
|
||||
public constructor(private _cachingService: CachingService, private _networkService: NetworkService) {
|
||||
public constructor(
|
||||
private _cachingService: CachingService,
|
||||
private _networkService: NetworkService,
|
||||
private _tocService: TocService
|
||||
) {
|
||||
super();
|
||||
this._circuitBreaker = this._networkService.getCircuitBreaker(`${this.name}_main`);
|
||||
}
|
||||
@@ -170,20 +175,23 @@ export class TukUiAddonProvider extends AddonProvider {
|
||||
const matches: TukUiAddon[] = [];
|
||||
|
||||
// Sort folders to prioritize ones with a toc id
|
||||
let sortedAddonFolders = _.orderBy(addonFolders, ["toc.tukUiProjectId"], ["desc"]);
|
||||
sortedAddonFolders = _.filter(sortedAddonFolders, (folder) => folder.toc.loadOnDemand !== "1");
|
||||
const tukProjectAddonFolders = addonFolders.filter((folder) =>
|
||||
folder.tocs.some((toc) => !!toc.tukUiProjectId && toc.loadOnDemand !== "1")
|
||||
);
|
||||
|
||||
for (const addonFolder of tukProjectAddonFolders) {
|
||||
const targetToc = this._tocService.getTocForGameType2(addonFolder.tocs, installation.clientType);
|
||||
|
||||
for (const addonFolder of sortedAddonFolders) {
|
||||
let tukUiAddon: TukUiAddon;
|
||||
if (addonFolder.toc?.tukUiProjectId) {
|
||||
const match = _.find(allAddons, (addon) => addon.id.toString() === addonFolder.toc.tukUiProjectId);
|
||||
if (targetToc?.tukUiProjectId) {
|
||||
const match = _.find(allAddons, (addon) => addon.id.toString() === targetToc.tukUiProjectId);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tukUiAddon = match;
|
||||
} else {
|
||||
const results = await this.searchAddons(addonFolder.toc.title, installation.clientType);
|
||||
const results = await this.searchAddons(targetToc.title, installation.clientType);
|
||||
const firstResult = _.first(results);
|
||||
if (!firstResult) {
|
||||
continue;
|
||||
@@ -193,7 +201,7 @@ export class TukUiAddonProvider extends AddonProvider {
|
||||
|
||||
// If we got a fuzzy name match, ensure it's not already added to prevent hiding addons
|
||||
if (tukUiAddon && _.findIndex(matches, (match) => match.id.toString() === tukUiAddon.id.toString()) !== -1) {
|
||||
console.warn(`Overlapping addon: ${addonFolder.toc.title ?? ""} => ${tukUiAddon.name}`);
|
||||
console.warn(`Overlapping addon: ${targetToc.title ?? ""} => ${tukUiAddon.name}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -204,12 +212,10 @@ export class TukUiAddonProvider extends AddonProvider {
|
||||
|
||||
matches.push({ ...tukUiAddon });
|
||||
|
||||
const installedFolders = addonFolder.toc.tukUiProjectFolders
|
||||
? addonFolder.toc.tukUiProjectFolders
|
||||
: tukUiAddon.name;
|
||||
const installedFolders = targetToc.tukUiProjectFolders ? targetToc.tukUiProjectFolders : tukUiAddon.name;
|
||||
|
||||
const installedFolderList = addonFolder.toc.tukUiProjectFolders
|
||||
? addonFolder.toc.tukUiProjectFolders.split(",").map((f) => f.trim())
|
||||
const installedFolderList = targetToc.tukUiProjectFolders
|
||||
? targetToc.tukUiProjectFolders.split(",").map((f) => f.trim())
|
||||
: [tukUiAddon.name];
|
||||
|
||||
addonFolder.matchingAddon = {
|
||||
@@ -227,7 +233,7 @@ export class TukUiAddonProvider extends AddonProvider {
|
||||
installedAt: addonFolder.fileStats?.birthtime ?? new Date(0),
|
||||
installedFolders: installedFolders,
|
||||
installedFolderList: installedFolderList,
|
||||
installedVersion: addonFolder.toc.version,
|
||||
installedVersion: targetToc.version,
|
||||
latestVersion: tukUiAddon.version,
|
||||
providerName: this.name,
|
||||
thumbnailUrl: tukUiAddon.screenshot_url,
|
||||
|
||||
@@ -21,6 +21,7 @@ import { convertBbcode } from "../utils/bbcode.utils";
|
||||
import { getEnumName } from "../utils/enum.utils";
|
||||
import { AddonProvider, GetAllResult } from "./addon-provider";
|
||||
import { strictFilter } from "../utils/array.utils";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
|
||||
const API_URL = "https://api.mmoui.com/v4/game/WOW";
|
||||
const ADDON_URL = "https://www.wowinterface.com/downloads/info";
|
||||
@@ -36,7 +37,11 @@ export class WowInterfaceAddonProvider extends AddonProvider {
|
||||
public readonly allowEdit = true;
|
||||
public enabled = true;
|
||||
|
||||
public constructor(private _cachingService: CachingService, private _networkService: NetworkService) {
|
||||
public constructor(
|
||||
private _cachingService: CachingService,
|
||||
private _networkService: NetworkService,
|
||||
private _tocService: TocService
|
||||
) {
|
||||
super();
|
||||
this._circuitBreaker = this._networkService.getCircuitBreaker(`${this.name}_main`);
|
||||
}
|
||||
@@ -136,15 +141,20 @@ export class WowInterfaceAddonProvider extends AddonProvider {
|
||||
addonChannelType: AddonChannelType,
|
||||
addonFolders: AddonFolder[]
|
||||
): Promise<void> {
|
||||
const addonIds = addonFolders.filter((af) => !!af.toc.wowInterfaceId).map((af) => af.toc.wowInterfaceId ?? "");
|
||||
const wowiFolders = addonFolders.filter((folder) =>
|
||||
folder.tocs.some((toc) => !!toc.wowInterfaceId && toc.loadOnDemand !== "1")
|
||||
);
|
||||
const addonIds = _.uniq(_.flatten(wowiFolders.map((folder) => folder.tocs.map((toc) => toc.wowInterfaceId))));
|
||||
|
||||
const addonDetails = await this.getAllAddonDetails(addonIds);
|
||||
|
||||
for (const addonFolder of addonFolders) {
|
||||
if (!addonFolder?.toc?.wowInterfaceId) {
|
||||
for (const addonFolder of wowiFolders) {
|
||||
const targetToc = this._tocService.getTocForGameType2(addonFolder.tocs, installation.clientType);
|
||||
if (!targetToc?.wowInterfaceId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const details = addonDetails.find((ad) => ad.id.toString() === addonFolder.toc.wowInterfaceId);
|
||||
const details = addonDetails.find((ad) => ad.id.toString() === targetToc.wowInterfaceId);
|
||||
if (!details) {
|
||||
console.warn("Details not found");
|
||||
continue;
|
||||
@@ -213,6 +223,8 @@ export class WowInterfaceAddonProvider extends AddonProvider {
|
||||
addonChannelType: AddonChannelType,
|
||||
addonFolder: AddonFolder
|
||||
): Addon {
|
||||
const targetToc = this._tocService.getTocForGameType2(addonFolder.tocs, installation.clientType);
|
||||
|
||||
return {
|
||||
id: uuidv4(),
|
||||
author: response.author,
|
||||
@@ -222,11 +234,11 @@ export class WowInterfaceAddonProvider extends AddonProvider {
|
||||
downloadUrl: response.downloadUri,
|
||||
externalId: response.id.toString(),
|
||||
externalUrl: this.getAddonUrl(response),
|
||||
gameVersion: getGameVersion(addonFolder.toc.interface),
|
||||
gameVersion: getGameVersion(targetToc.interface),
|
||||
installedAt: new Date(),
|
||||
installedFolders: addonFolder.name,
|
||||
installedFolderList: [addonFolder.name],
|
||||
installedVersion: addonFolder.toc?.version,
|
||||
installedVersion: targetToc?.version,
|
||||
isIgnored: false,
|
||||
latestVersion: response.version,
|
||||
name: response.title,
|
||||
|
||||
@@ -4,8 +4,10 @@ import { v4 as uuidv4 } from "uuid";
|
||||
import { ADDON_PROVIDER_WOWUP_COMPANION, WOWUP_DATA_ADDON_FOLDER_NAME } from "../../common/constants";
|
||||
import { AddonChannelType } from "../../common/wowup/models";
|
||||
import { AddonFolder } from "../models/wowup/addon-folder";
|
||||
import { Toc } from "../models/wowup/toc";
|
||||
import { WowInstallation } from "../models/wowup/wow-installation";
|
||||
import { FileService } from "../services/files/file.service";
|
||||
import { TocService } from "../services/toc/toc.service";
|
||||
import { getGameVersion } from "../utils/addon.utils";
|
||||
import { getEnumName } from "../utils/enum.utils";
|
||||
import { AddonProvider } from "./addon-provider";
|
||||
@@ -21,7 +23,7 @@ export class WowUpCompanionAddonProvider extends AddonProvider {
|
||||
public readonly allowEdit = false;
|
||||
public enabled = true;
|
||||
|
||||
public constructor(private _fileService: FileService) {
|
||||
public constructor(private _fileService: FileService, private _tocService: TocService) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -35,6 +37,7 @@ export class WowUpCompanionAddonProvider extends AddonProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetToc = this._tocService.getTocForGameType2(companion.tocs, installation.clientType);
|
||||
const lastUpdatedAt = await this._fileService.getLatestDirUpdateTime(companion.path);
|
||||
|
||||
companion.matchingAddon = {
|
||||
@@ -43,25 +46,25 @@ export class WowUpCompanionAddonProvider extends AddonProvider {
|
||||
clientType: installation.clientType,
|
||||
id: uuidv4(),
|
||||
isIgnored: true,
|
||||
name: companion.toc.title ?? "unknown",
|
||||
author: companion.toc.author ?? "unknown",
|
||||
name: targetToc.title ?? "unknown",
|
||||
author: targetToc.author ?? "unknown",
|
||||
downloadUrl: "",
|
||||
externalId: this.name,
|
||||
externalUrl: X_WEBSITE,
|
||||
gameVersion: getGameVersion(companion.toc.interface),
|
||||
gameVersion: getGameVersion(targetToc.interface),
|
||||
installedAt: new Date(lastUpdatedAt),
|
||||
installedFolders: companion.name,
|
||||
installedFolderList: [companion.name],
|
||||
installedVersion: companion.toc.version,
|
||||
latestVersion: companion.toc.version,
|
||||
installedVersion: targetToc.version,
|
||||
latestVersion: targetToc.version,
|
||||
providerName: this.name,
|
||||
thumbnailUrl: "https://avatars.githubusercontent.com/u/74023737?s=400&v=4",
|
||||
updatedAt: new Date(lastUpdatedAt),
|
||||
summary: companion.toc.notes,
|
||||
summary: targetToc.notes,
|
||||
downloadCount: 0,
|
||||
screenshotUrls: [],
|
||||
releasedAt: new Date(lastUpdatedAt),
|
||||
isLoadOnDemand: companion.toc.loadOnDemand === "1",
|
||||
isLoadOnDemand: targetToc.loadOnDemand === "1",
|
||||
externalChannel: getEnumName(AddonChannelType, AddonChannelType.Stable),
|
||||
installationId: installation.id,
|
||||
};
|
||||
@@ -70,8 +73,8 @@ export class WowUpCompanionAddonProvider extends AddonProvider {
|
||||
private isWowUpCompanion(addonFolder: AddonFolder) {
|
||||
return (
|
||||
addonFolder.name === WOWUP_DATA_ADDON_FOLDER_NAME &&
|
||||
addonFolder.toc?.website === X_WEBSITE &&
|
||||
addonFolder.toc?.addonProvider === X_WOWUP_ADDON_PROVIDER
|
||||
addonFolder.tocs?.some((toc) => toc.website === X_WEBSITE) &&
|
||||
addonFolder.tocs?.some((toc) => toc.addonProvider === X_WOWUP_ADDON_PROVIDER)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ import {
|
||||
IPC_REQUEST_INSTALL_FROM_URL,
|
||||
WOWUP_LOGO_FILENAME,
|
||||
} from "../common/constants";
|
||||
import { MenuConfig, SystemTrayConfig } from "../common/wowup/models";
|
||||
import { AppUpdateState, MenuConfig, SystemTrayConfig } from "../common/wowup/models";
|
||||
import { TelemetryDialogComponent } from "./components/telemetry-dialog/telemetry-dialog.component";
|
||||
import { ElectronService } from "./services";
|
||||
import { AddonService } from "./services/addons/addon.service";
|
||||
@@ -50,6 +50,7 @@ import { AddonSyncError, GitHubFetchReleasesError, GitHubFetchRepositoryError, G
|
||||
import { SnackbarService } from "./services/snackbar/snackbar.service";
|
||||
import { WarcraftInstallationService } from "./services/warcraft/warcraft-installation.service";
|
||||
import { ZoomService } from "./services/zoom/zoom.service";
|
||||
import { AlertDialogComponent } from "./components/alert-dialog/alert-dialog.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-root",
|
||||
@@ -103,6 +104,31 @@ export class AppComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||
switchMap(() => from(this.initializeAutoUpdate()))
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
this.electronService.appUpdate$.subscribe((evt) => {
|
||||
if (evt.state === AppUpdateState.Error) {
|
||||
if (evt.error.indexOf("dev-app-update.yml") === -1) {
|
||||
this._snackbarService.showErrorSnackbar("APP.WOWUP_UPDATE.UPDATE_ERROR");
|
||||
}
|
||||
} else if (evt.state === AppUpdateState.Downloaded) {
|
||||
// Force the user to update when one is ready
|
||||
const dialogRef = this._dialog.open(AlertDialogComponent, {
|
||||
minWidth: 250,
|
||||
disableClose: true,
|
||||
data: {
|
||||
title: this.translate.instant("APP.WOWUP_UPDATE.INSTALL_TITLE"),
|
||||
message: this.translate.instant("APP.WOWUP_UPDATE.SNACKBAR_TEXT"),
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(first())
|
||||
.subscribe(() => {
|
||||
this.wowUpService.installUpdate();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
|
||||
@@ -3,17 +3,25 @@
|
||||
<div class="row align-items-center text-1">
|
||||
<p class="mr-3">{{ sessionService.pageContextText$ | async }}</p>
|
||||
<p>v{{ versionNumber | async }}</p>
|
||||
<button *ngIf="isWowUpUpdateAvailable && !isWowUpdateDownloading" class="footer-button update-button ml-3 text-1"
|
||||
matTooltip="{{ updateIconTooltip | translate }}" [disabled]="isUpdatingWowUp" (click)="onClickUpdateWowup()">
|
||||
<h4>{{ 'APP.WOWUP_UPDATE.SNACKBAR_ACTION' | translate }}</h4>
|
||||
</button>
|
||||
<button *ngIf="isWowUpdateDownloading" class="footer-button downloading-button text-2 ml-3 animate">
|
||||
<mat-icon svgIcon="fas:angle-double-down"></mat-icon>
|
||||
</button>
|
||||
<button *ngIf="!isWowUpUpdateAvailable && !isWowUpdateDownloading"
|
||||
class="footer-button text-1 check-update-button ml-3" [ngClass]="{ animate: isCheckingForUpdates }"
|
||||
(click)="onClickCheckForUpdates()" matTooltip="{{ 'APP.SYSTEM_TRAY.CHECK_UPDATE' | translate }}">
|
||||
<mat-icon svgIcon="fas:sync-alt"></mat-icon>
|
||||
</button>
|
||||
<div class="ml-3" [ngSwitch]="appUpdateState$ | async">
|
||||
<div *ngSwitchCase="appUpdateState.CheckingForUpdate">{{'APP.WOWUP_UPDATE.CHECKING_FOR_UPDATE' | translate}}</div>
|
||||
<div *ngSwitchCase="appUpdateState.Downloading" class="row align-items-center">
|
||||
<mat-progress-spinner class="" color="primary" mode="determinate" [value]="appUpdateProgress$ | async"
|
||||
[diameter]="20"></mat-progress-spinner>
|
||||
<span>{{'APP.WOWUP_UPDATE.DOWNLOADING_UPDATE' | translate}}</span>
|
||||
</div>
|
||||
<div *ngSwitchCase="appUpdateState.Downloaded">
|
||||
<button class="footer-button update-button ml-3 text-1" matTooltip="{{ updateIconTooltip | translate }}"
|
||||
(click)="onClickInstallUpdate()">
|
||||
<h4>{{ 'APP.WOWUP_UPDATE.SNACKBAR_ACTION' | translate }}</h4>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngSwitchDefault>
|
||||
<button class="footer-button text-1 check-update-button ml-3" (click)="onClickCheckForUpdates()"
|
||||
matTooltip="{{ 'APP.SYSTEM_TRAY.CHECK_UPDATE' | translate }}">
|
||||
<mat-icon svgIcon="fas:sync-alt"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
@@ -29,7 +29,6 @@ describe("FooterComponent", () => {
|
||||
getApplicationVersion: () => Promise.resolve("TESTV"),
|
||||
wowupUpdateCheck$: new Subject<UpdateCheckResult>().asObservable(),
|
||||
wowupUpdateDownloaded$: new Subject<any>().asObservable(),
|
||||
wowupUpdateCheckInProgress$: new Subject<boolean>().asObservable(),
|
||||
wowupUpdateDownloadInProgress$: new Subject<boolean>().asObservable(),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ChangeDetectorRef, Component, NgZone, OnInit } from "@angular/core";
|
||||
import { Component, NgZone, OnInit } from "@angular/core";
|
||||
import { MatDialog } from "@angular/material/dialog";
|
||||
import { TranslateService } from "@ngx-translate/core";
|
||||
import { ElectronService } from "../../services";
|
||||
@@ -7,9 +7,10 @@ import { AppConfig } from "../../../environments/environment";
|
||||
import { SessionService } from "../../services/session/session.service";
|
||||
import { WowUpService } from "../../services/wowup/wowup.service";
|
||||
import { ConfirmDialogComponent } from "../confirm-dialog/confirm-dialog.component";
|
||||
import { from, of } from "rxjs";
|
||||
import { combineLatest, from, Observable, of } from "rxjs";
|
||||
import { SnackbarService } from "../../services/snackbar/snackbar.service";
|
||||
import { catchError, switchMap } from "rxjs/operators";
|
||||
import { catchError, map, switchMap } from "rxjs/operators";
|
||||
import { AppUpdateState } from "../../../common/wowup/models";
|
||||
|
||||
@Component({
|
||||
selector: "app-footer",
|
||||
@@ -24,48 +25,27 @@ export class FooterComponent implements OnInit {
|
||||
public isWowUpdateDownloading = false;
|
||||
public updateIconTooltip = "APP.WOWUP_UPDATE.TOOLTIP";
|
||||
public versionNumber = from(this.wowUpService.getApplicationVersion());
|
||||
public appUpdateState = AppUpdateState;
|
||||
|
||||
public appUpdateState$: Observable<AppUpdateState> = this.electronService.appUpdate$.pipe(map((evt) => evt.state));
|
||||
|
||||
public appUpdateProgress$: Observable<number> = combineLatest([
|
||||
of(0),
|
||||
this.electronService.appUpdate$.pipe(map((evt) => evt.progress?.percent ?? 0)),
|
||||
]).pipe(map(([def, val]) => Math.max(def, val)));
|
||||
|
||||
public constructor(
|
||||
private _dialog: MatDialog,
|
||||
private _translateService: TranslateService,
|
||||
private _zone: NgZone,
|
||||
private _cdRef: ChangeDetectorRef,
|
||||
public wowUpService: WowUpService,
|
||||
public sessionService: SessionService,
|
||||
private _snackBarService: SnackbarService,
|
||||
private _electronService: ElectronService,
|
||||
private electronService: ElectronService,
|
||||
private _wowupService: WowUpService
|
||||
) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.wowUpService.wowupUpdateCheck$.subscribe((updateCheckResult) => {
|
||||
console.debug("updateCheckResult", updateCheckResult);
|
||||
this.isWowUpUpdateAvailable = true;
|
||||
this._snackBarService.showSuccessSnackbar("APP.WOWUP_UPDATE.SNACKBAR_TEXT");
|
||||
this._cdRef.detectChanges();
|
||||
});
|
||||
|
||||
this.wowUpService.wowupUpdateDownloaded$.subscribe((result) => {
|
||||
console.debug("wowupUpdateDownloaded", result);
|
||||
this._zone.run(() => {
|
||||
this.isWowUpUpdateDownloaded = true;
|
||||
this.updateIconTooltip = "APP.WOWUP_UPDATE.DOWNLOADED_TOOLTIP";
|
||||
this.onClickUpdateWowup().catch((e) => console.error(e));
|
||||
});
|
||||
});
|
||||
|
||||
this.wowUpService.wowupUpdateCheckInProgress$.subscribe((inProgress) => {
|
||||
console.debug("wowUpUpdateCheckInProgress", inProgress);
|
||||
this.isCheckingForUpdates = inProgress;
|
||||
this._cdRef.detectChanges();
|
||||
});
|
||||
|
||||
this.wowUpService.wowupUpdateDownloadInProgress$.subscribe((inProgress) => {
|
||||
console.debug("wowupUpdateDownloadInProgress", inProgress);
|
||||
this.isWowUpdateDownloading = inProgress;
|
||||
this._cdRef.detectChanges();
|
||||
});
|
||||
|
||||
// Force the angular zone to pump for every progress update since its outside the zone
|
||||
this.sessionService.statusText$.subscribe(() => {
|
||||
this._zone.run(() => {});
|
||||
@@ -76,22 +56,8 @@ export class FooterComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
public async onClickCheckForUpdates(): Promise<void> {
|
||||
if (this.isCheckingForUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result: UpdateCheckResult | null = null;
|
||||
try {
|
||||
result = await this.wowUpService.checkForAppUpdate();
|
||||
|
||||
if (result === null || (await this.wowUpService.isSameVersion(result))) {
|
||||
this._snackBarService.showSnackbar("APP.WOWUP_UPDATE.NOT_AVAILABLE");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this._snackBarService.showErrorSnackbar("APP.WOWUP_UPDATE.UPDATE_ERROR");
|
||||
}
|
||||
public onClickCheckForUpdates(): void {
|
||||
this.wowUpService.checkForAppUpdate();
|
||||
}
|
||||
|
||||
private portableUpdate() {
|
||||
@@ -126,50 +92,54 @@ export class FooterComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
public async onClickUpdateWowup(): Promise<void> {
|
||||
if (!this.isWowUpUpdateAvailable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._electronService.isPortable) {
|
||||
this.portableUpdate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isWowUpUpdateDownloaded) {
|
||||
const dialogRef = this._dialog.open(ConfirmDialogComponent, {
|
||||
data: {
|
||||
title: this._translateService.instant("APP.WOWUP_UPDATE.INSTALL_TITLE"),
|
||||
message: this._translateService.instant("APP.WOWUP_UPDATE.INSTALL_MESSAGE"),
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
switchMap((result) => {
|
||||
if (!result) {
|
||||
return of(undefined);
|
||||
}
|
||||
return from(this.wowUpService.installUpdate());
|
||||
}),
|
||||
catchError((e) => {
|
||||
console.error(e);
|
||||
return of(undefined);
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.isUpdatingWowUp = true;
|
||||
try {
|
||||
await this.wowUpService.downloadUpdate();
|
||||
} catch (e) {
|
||||
console.error("onClickUpdateWowup", e);
|
||||
} finally {
|
||||
this.isUpdatingWowUp = false;
|
||||
}
|
||||
public onClickInstallUpdate(): void {
|
||||
this._wowupService.installUpdate();
|
||||
}
|
||||
|
||||
// public async onClickUpdateWowup(): Promise<void> {
|
||||
// if (!this.isWowUpUpdateAvailable) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (this.electronService.isPortable) {
|
||||
// this.portableUpdate();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (this.isWowUpUpdateDownloaded) {
|
||||
// const dialogRef = this._dialog.open(ConfirmDialogComponent, {
|
||||
// data: {
|
||||
// title: this._translateService.instant("APP.WOWUP_UPDATE.INSTALL_TITLE"),
|
||||
// message: this._translateService.instant("APP.WOWUP_UPDATE.INSTALL_MESSAGE"),
|
||||
// },
|
||||
// });
|
||||
|
||||
// dialogRef
|
||||
// .afterClosed()
|
||||
// .pipe(
|
||||
// switchMap((result) => {
|
||||
// if (!result) {
|
||||
// return of(undefined);
|
||||
// }
|
||||
// return from(this.wowUpService.installUpdate());
|
||||
// }),
|
||||
// catchError((e) => {
|
||||
// console.error(e);
|
||||
// return of(undefined);
|
||||
// })
|
||||
// )
|
||||
// .subscribe();
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
// this.isUpdatingWowUp = true;
|
||||
// try {
|
||||
// await this.wowUpService.downloadUpdate();
|
||||
// } catch (e) {
|
||||
// console.error("onClickUpdateWowup", e);
|
||||
// } finally {
|
||||
// this.isUpdatingWowUp = false;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ export interface AddonFolder {
|
||||
ignoreReason?: AddonIgnoreReason;
|
||||
thumbnailUrl?: string;
|
||||
latestVersion?: string;
|
||||
toc: Toc;
|
||||
tocMetaData: string[];
|
||||
tocs: Toc[];
|
||||
matchingAddon?: Addon;
|
||||
fileStats?: FsStats;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface Toc {
|
||||
fileName: string;
|
||||
interface: string;
|
||||
title?: string;
|
||||
author?: string;
|
||||
|
||||
@@ -155,10 +155,8 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
|
||||
|
||||
// check for an app update every so often
|
||||
this._appUpdateInterval = window.setInterval(() => {
|
||||
this.checkForAppUpdate().catch((e) => console.error(e));
|
||||
this._wowupService.checkForAppUpdate();
|
||||
}, AppConfig.appUpdateIntervalMs);
|
||||
|
||||
this.checkForAppUpdate().catch((e) => console.error(e));
|
||||
}
|
||||
|
||||
private destroyAppUpdateCheck() {
|
||||
@@ -245,15 +243,6 @@ export class HomeComponent implements AfterViewInit, OnDestroy {
|
||||
}
|
||||
};
|
||||
|
||||
private async checkForAppUpdate() {
|
||||
try {
|
||||
const appUpdateResponse = await this._wowupService.checkForAppUpdate();
|
||||
console.log(appUpdateResponse);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private onAddonInstalledEvent = (evt: AddonUpdateEvent) => {
|
||||
if (evt.installState !== AddonInstallState.Error) {
|
||||
return;
|
||||
|
||||
@@ -37,11 +37,11 @@ export class AddonProviderFactory {
|
||||
) {}
|
||||
|
||||
public createWowUpCompanionAddonProvider(): WowUpCompanionAddonProvider {
|
||||
return new WowUpCompanionAddonProvider(this._fileService);
|
||||
return new WowUpCompanionAddonProvider(this._fileService, this._tocService);
|
||||
}
|
||||
|
||||
public createRaiderIoAddonProvider(): RaiderIoAddonProvider {
|
||||
return new RaiderIoAddonProvider();
|
||||
return new RaiderIoAddonProvider(this._tocService);
|
||||
}
|
||||
|
||||
public createCurseAddonProvider(): CurseAddonProvider {
|
||||
@@ -49,16 +49,17 @@ export class AddonProviderFactory {
|
||||
this._cachingService,
|
||||
this._electronService,
|
||||
this._wowupApiService,
|
||||
this._tocService,
|
||||
this._networkService
|
||||
);
|
||||
}
|
||||
|
||||
public createTukUiAddonProvider(): TukUiAddonProvider {
|
||||
return new TukUiAddonProvider(this._cachingService, this._networkService);
|
||||
return new TukUiAddonProvider(this._cachingService, this._networkService, this._tocService);
|
||||
}
|
||||
|
||||
public createWowInterfaceAddonProvider(): WowInterfaceAddonProvider {
|
||||
return new WowInterfaceAddonProvider(this._cachingService, this._networkService);
|
||||
return new WowInterfaceAddonProvider(this._cachingService, this._networkService, this._tocService);
|
||||
}
|
||||
|
||||
public createGitHubAddonProvider(): GitHubAddonProvider {
|
||||
|
||||
@@ -1438,7 +1438,7 @@ export class AddonService {
|
||||
|
||||
for (const provider of this.getEnabledAddonProviders()) {
|
||||
try {
|
||||
const validFolders = addonFolders.filter((af) => !af.ignoreReason && !af.matchingAddon && af.toc);
|
||||
const validFolders = addonFolders.filter((af) => !af.ignoreReason && !af.matchingAddon && af.tocs.length > 0);
|
||||
await provider.scan(installation, defaultAddonChannel, validFolders);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -1456,7 +1456,8 @@ export class AddonService {
|
||||
|
||||
matchedAddonFolders.forEach((maf) => {
|
||||
if (maf.matchingAddon) {
|
||||
this.setExternalIds(maf.matchingAddon, maf.toc);
|
||||
const targetToc = this._tocService.getTocForGameType2(maf.tocs, installation.clientType);
|
||||
this.setExternalIds(maf.matchingAddon, targetToc);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1466,6 +1467,8 @@ export class AddonService {
|
||||
`${addonFolder.matchingAddon?.providerName ?? ""}${addonFolder.matchingAddon?.externalId ?? ""}`
|
||||
);
|
||||
|
||||
console.debug("matchedGroups", matchedGroups);
|
||||
|
||||
const addonList: Addon[] = [];
|
||||
for (const value of Object.values(matchedGroups)) {
|
||||
const ordered = _.orderBy(value, (v) => v.matchingAddon?.externalIds?.length ?? 0).reverse();
|
||||
@@ -1478,7 +1481,9 @@ export class AddonService {
|
||||
// (value) => _.orderBy(value, (v) => v.matchingAddon?.externalIds?.length ?? 0).reverse()[0].matchingAddon
|
||||
// );
|
||||
|
||||
const unmatchedFolders = addonFolders.filter((af) => this.isAddonFolderUnmatched(matchedAddonFolderNames, af));
|
||||
const unmatchedFolders = addonFolders.filter((af) =>
|
||||
this.isAddonFolderUnmatched(matchedAddonFolderNames, af, installation)
|
||||
);
|
||||
|
||||
for (const uf of unmatchedFolders) {
|
||||
const unmatchedAddon = await this.createUnmatchedAddon(uf, installation, matchedAddonFolderNames);
|
||||
@@ -1518,7 +1523,7 @@ export class AddonService {
|
||||
if (!addon.providerName || !addon.externalId) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
this.insertExternalId(externalIds, addon.providerName, addon.externalId);
|
||||
}
|
||||
|
||||
@@ -1554,14 +1559,20 @@ export class AddonService {
|
||||
* This should verify that a folder that did not have a match, is actually unmatched
|
||||
* This will happen for any sub folders of TukUI or WowInterface addons
|
||||
*/
|
||||
private isAddonFolderUnmatched(matchedFolderNames: string[], addonFolder: AddonFolder) {
|
||||
private isAddonFolderUnmatched(
|
||||
matchedFolderNames: string[],
|
||||
addonFolder: AddonFolder,
|
||||
installation: WowInstallation
|
||||
) {
|
||||
if (addonFolder.matchingAddon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetToc = this._tocService.getTocForGameType2(addonFolder.tocs, installation.clientType);
|
||||
|
||||
// if the folder is load on demand, it 'should' be a sub folder
|
||||
const isLoadOnDemand = addonFolder.toc?.loadOnDemand === "1";
|
||||
if (isLoadOnDemand && this.allItemsMatch(addonFolder.toc.dependencyList, matchedFolderNames)) {
|
||||
const isLoadOnDemand = targetToc?.loadOnDemand === "1";
|
||||
if (isLoadOnDemand && this.allItemsMatch(targetToc.dependencyList, matchedFolderNames)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1832,8 +1843,8 @@ export class AddonService {
|
||||
};
|
||||
}
|
||||
|
||||
private hasValidTocTitle(addonFolder: AddonFolder) {
|
||||
return addonFolder.toc?.title && /[a-zA-Z]/g.test(addonFolder.toc.title);
|
||||
private hasValidTocTitle(toc: Toc) {
|
||||
return toc?.title && /[a-zA-Z]/g.test(toc.title);
|
||||
}
|
||||
|
||||
private async createUnmatchedAddon(
|
||||
@@ -1841,19 +1852,20 @@ export class AddonService {
|
||||
installation: WowInstallation,
|
||||
matchedAddonFolderNames: string[]
|
||||
): Promise<Addon> {
|
||||
const tocMissingDependencies = _.difference(addonFolder.toc?.dependencyList, matchedAddonFolderNames);
|
||||
const targetToc = this._tocService.getTocForGameType2(addonFolder.tocs, installation.clientType);
|
||||
const tocMissingDependencies = _.difference(targetToc?.dependencyList, matchedAddonFolderNames);
|
||||
const lastUpdatedAt = await this._fileService.getLatestDirUpdateTime(addonFolder.path);
|
||||
|
||||
return {
|
||||
id: uuidv4(),
|
||||
name: this.hasValidTocTitle(addonFolder) ? addonFolder.toc.title ?? addonFolder.name : addonFolder.name,
|
||||
name: this.hasValidTocTitle(targetToc) ? targetToc.title ?? addonFolder.name : addonFolder.name,
|
||||
thumbnailUrl: "",
|
||||
latestVersion: addonFolder.toc?.version || "",
|
||||
installedVersion: addonFolder.toc?.version || "",
|
||||
latestVersion: targetToc?.version || "",
|
||||
installedVersion: targetToc?.version || "",
|
||||
clientType: installation.clientType,
|
||||
externalId: "",
|
||||
gameVersion: AddonUtils.getGameVersion(addonFolder.toc?.interface) || "",
|
||||
author: addonFolder.toc?.author || "",
|
||||
gameVersion: AddonUtils.getGameVersion(targetToc?.interface) || "",
|
||||
author: targetToc?.author || "",
|
||||
downloadUrl: "",
|
||||
externalUrl: "",
|
||||
providerName: ADDON_PROVIDER_UNKNOWN,
|
||||
@@ -1866,7 +1878,7 @@ export class AddonService {
|
||||
installedFolderList: [addonFolder.name],
|
||||
summary: "",
|
||||
screenshotUrls: [],
|
||||
isLoadOnDemand: addonFolder.toc?.loadOnDemand === "1",
|
||||
isLoadOnDemand: targetToc?.loadOnDemand === "1",
|
||||
externalChannel: getEnumName(AddonChannelType, AddonChannelType.Stable),
|
||||
missingDependencies: tocMissingDependencies,
|
||||
ignoreReason: addonFolder.ignoreReason,
|
||||
|
||||
@@ -4,16 +4,13 @@ import { IpcRendererEvent, OpenDialogOptions, OpenDialogReturnValue, OpenExterna
|
||||
import { LoginItemSettings } from "electron/main";
|
||||
import { find } from "lodash";
|
||||
import * as minimist from "minimist";
|
||||
import { BehaviorSubject } from "rxjs";
|
||||
import { BehaviorSubject, ReplaySubject } from "rxjs";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { Injectable } from "@angular/core";
|
||||
|
||||
import {
|
||||
APP_UPDATE_CHECK_END,
|
||||
APP_UPDATE_CHECK_START,
|
||||
APP_UPDATE_DOWNLOADED,
|
||||
APP_UPDATE_START_DOWNLOAD,
|
||||
IPC_APP_UPDATE_STATE,
|
||||
IPC_CLOSE_WINDOW,
|
||||
IPC_CUSTOM_PROTOCOL_RECEIVED,
|
||||
IPC_FOCUS_WINDOW,
|
||||
@@ -47,7 +44,7 @@ import { IpcResponse } from "../../../common/models/ipc-response";
|
||||
import { ValueRequest } from "../../../common/models/value-request";
|
||||
import { ValueResponse } from "../../../common/models/value-response";
|
||||
import { MainChannels, RendererChannels } from "../../../common/wowup";
|
||||
import { AppOptions } from "../../../common/wowup/models";
|
||||
import { AppOptions, AppUpdateEvent } from "../../../common/wowup/models";
|
||||
import { isProtocol } from "../../utils/string.utils";
|
||||
|
||||
@Injectable({
|
||||
@@ -56,18 +53,18 @@ import { isProtocol } from "../../utils/string.utils";
|
||||
export class ElectronService {
|
||||
private readonly _windowMaximizedSrc = new BehaviorSubject(false);
|
||||
private readonly _windowMinimizedSrc = new BehaviorSubject(false);
|
||||
private readonly _ipcEventReceivedSrc = new BehaviorSubject("");
|
||||
private readonly _powerMonitorSrc = new BehaviorSubject("");
|
||||
private readonly _customProtocolSrc = new BehaviorSubject("");
|
||||
private readonly _appUpdateSrc = new ReplaySubject<AppUpdateEvent>();
|
||||
|
||||
private _appVersion = "";
|
||||
private _opts!: AppOptions;
|
||||
|
||||
public readonly windowMaximized$ = this._windowMaximizedSrc.asObservable();
|
||||
public readonly windowMinimized$ = this._windowMinimizedSrc.asObservable();
|
||||
public readonly ipcEventReceived$ = this._ipcEventReceivedSrc.asObservable();
|
||||
public readonly powerMonitor$ = this._powerMonitorSrc.asObservable();
|
||||
public readonly customProtocol$ = this._customProtocolSrc.asObservable();
|
||||
public readonly appUpdate$ = this._appUpdateSrc.asObservable();
|
||||
public readonly isWin = process.platform === "win32";
|
||||
public readonly isMac = process.platform === "darwin";
|
||||
public readonly isLinux = process.platform === "linux";
|
||||
@@ -100,20 +97,10 @@ export class ElectronService {
|
||||
console.error("Failed to get app version", e);
|
||||
});
|
||||
|
||||
this.onRendererEvent(APP_UPDATE_CHECK_START, () => {
|
||||
this._ipcEventReceivedSrc.next(APP_UPDATE_CHECK_START);
|
||||
});
|
||||
|
||||
this.onRendererEvent(APP_UPDATE_CHECK_END, () => {
|
||||
this._ipcEventReceivedSrc.next(APP_UPDATE_CHECK_END);
|
||||
});
|
||||
|
||||
this.onRendererEvent(APP_UPDATE_START_DOWNLOAD, () => {
|
||||
this._ipcEventReceivedSrc.next(APP_UPDATE_START_DOWNLOAD);
|
||||
});
|
||||
|
||||
this.onRendererEvent(APP_UPDATE_DOWNLOADED, () => {
|
||||
this._ipcEventReceivedSrc.next(APP_UPDATE_DOWNLOADED);
|
||||
this.onRendererEvent(IPC_APP_UPDATE_STATE, (evt, updateEvt: AppUpdateEvent) => {
|
||||
console.log("IPC_APP_UPDATE_STATE", IPC_APP_UPDATE_STATE);
|
||||
console.log(updateEvt);
|
||||
this._appUpdateSrc.next(updateEvt);
|
||||
});
|
||||
|
||||
this.onRendererEvent(IPC_WINDOW_MINIMIZED, () => {
|
||||
@@ -305,7 +292,12 @@ export class ElectronService {
|
||||
}
|
||||
|
||||
public async invoke<T = any>(channel: RendererChannels, ...args: any[]): Promise<T> {
|
||||
return await window.wowup.rendererInvoke(channel, ...args);
|
||||
try {
|
||||
return await window.wowup.rendererInvoke(channel, ...args);
|
||||
} catch (e) {
|
||||
console.error("Invoke failed", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public on(channel: string, listener: (event: IpcRendererEvent, ...args: any[]) => void): void {
|
||||
|
||||
@@ -31,6 +31,7 @@ export class TocService {
|
||||
public constructor(private _fileService: FileService) {}
|
||||
|
||||
public async parse(tocPath: string): Promise<Toc> {
|
||||
const fileName = path.basename(tocPath);
|
||||
let tocText = await this._fileService.readFile(tocPath);
|
||||
tocText = tocText.trim();
|
||||
|
||||
@@ -39,6 +40,7 @@ export class TocService {
|
||||
const dependencyList: string[] = this.getDependencyList(tocText);
|
||||
|
||||
return {
|
||||
fileName,
|
||||
author: this.getValue(TOC_AUTHOR, tocText),
|
||||
curseProjectId: this.getValue(TOC_X_CURSE_PROJECT_ID, tocText),
|
||||
interface: this.getValue(TOC_INTERFACE, tocText),
|
||||
@@ -133,6 +135,33 @@ export class TocService {
|
||||
return matchedToc || tocFileNames.find((tfn) => /.*(?<!-classic|-bcc|-mainline)\.toc$/gi.test(tfn)) || "";
|
||||
}
|
||||
|
||||
public getTocForGameType2(tocs: Toc[], clientType: WowClientType): Toc {
|
||||
let matchedToc = "";
|
||||
|
||||
const tocFileNames = tocs.map((toc) => toc.fileName);
|
||||
switch (clientType) {
|
||||
case WowClientType.Beta:
|
||||
case WowClientType.Retail:
|
||||
case WowClientType.RetailPtr:
|
||||
matchedToc = tocFileNames.find((tfn) => /.*-mainline\.toc$/gi.test(tfn)) || "";
|
||||
break;
|
||||
case WowClientType.ClassicEra:
|
||||
matchedToc = tocFileNames.find((tfn) => /.*-classic\.toc$/gi.test(tfn)) || "";
|
||||
break;
|
||||
case WowClientType.Classic:
|
||||
case WowClientType.ClassicBeta:
|
||||
case WowClientType.ClassicPtr:
|
||||
matchedToc = tocFileNames.find((tfn) => /.*-bcc\.toc$/gi.test(tfn)) || "";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
matchedToc = matchedToc || tocFileNames.find((tfn) => /.*(?<!-classic|-bcc|-mainline)\.toc$/gi.test(tfn)) || "";
|
||||
|
||||
return tocs.find((toc) => toc.fileName === matchedToc);
|
||||
}
|
||||
|
||||
private getWebsite(tocText: string) {
|
||||
return this.getValue(TOC_WEBSITE, tocText) || this.getValue(TOC_X_WEBSITE, tocText);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import { WarcraftServiceImpl } from "./warcraft.service.impl";
|
||||
import { WarcraftServiceLinux } from "./warcraft.service.linux";
|
||||
import { WarcraftServiceMac } from "./warcraft.service.mac";
|
||||
import { WarcraftServiceWin } from "./warcraft.service.win";
|
||||
import { Toc } from "../../models/wowup/toc";
|
||||
|
||||
// WOW STRINGS
|
||||
|
||||
@@ -174,21 +175,23 @@ export class WarcraftService {
|
||||
try {
|
||||
const dirPath = path.join(addonFolderPath, dir);
|
||||
const dirFiles = await this._fileService.readdir(dirPath);
|
||||
const tocFile = dirFiles.find((f) => path.extname(f) === ".toc");
|
||||
if (!tocFile) {
|
||||
const tocFiles = dirFiles.filter((f) => path.extname(f) === ".toc");
|
||||
if (tocFiles.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const tocPath = path.join(dirPath, tocFile);
|
||||
const toc = await this._tocService.parse(tocPath);
|
||||
const tocMetaData = await this._tocService.parseMetaData(tocPath);
|
||||
const tocs: Toc[] = [];
|
||||
for (const tocFile of tocFiles) {
|
||||
const tocPath = path.join(dirPath, tocFile);
|
||||
const toc = await this._tocService.parse(tocPath);
|
||||
tocs.push(toc);
|
||||
}
|
||||
|
||||
return {
|
||||
name: dir,
|
||||
path: dirPath,
|
||||
status: "Pending",
|
||||
toc: toc,
|
||||
tocMetaData: tocMetaData,
|
||||
tocs: tocs,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
@@ -26,10 +26,11 @@ const CHANGELOGS: ChangeLog[] = [
|
||||
<img style="width: 200px;" loading="lazy" src="https://www.warcrafttavern.com/wp-content/uploads/2020/10/Warcraft-Tavern-Logo-768x246.png">
|
||||
</a>
|
||||
</li>
|
||||
<li>Mac M1 build available</li>
|
||||
</ul>
|
||||
<h4 style="margin-top: 1em;">Changes</h4>
|
||||
<ul>
|
||||
<li>Russian locale updates (Medok)</li>
|
||||
<li>German locale updates (Glow)</li>
|
||||
<li>Revamped UI</li>
|
||||
<li>WowUp updates will now download automatically</li>
|
||||
<li>When starting with 0 installs found, user should go to installations page</li>
|
||||
@@ -40,6 +41,8 @@ const CHANGELOGS: ChangeLog[] = [
|
||||
<li>Fixed an issue with table header font in addon details</li>
|
||||
<li>Fixed an issue with odd table de-select behavior</li>
|
||||
<li>Fixed an issue with the client selector overlapping the top toolbar</li>
|
||||
<li>Fixed an issue with re-scanning not showing the correct game version</li>
|
||||
<li>Reworked the app update flow</li>
|
||||
</ul>
|
||||
</div>`,
|
||||
},
|
||||
|
||||
@@ -9,25 +9,16 @@ import { TranslateService } from "@ngx-translate/core";
|
||||
import {
|
||||
ADDON_MIGRATION_VERSION_KEY,
|
||||
ADDON_PROVIDERS_KEY,
|
||||
ALLIANCE_LIGHT_THEME,
|
||||
ALLIANCE_THEME,
|
||||
APP_UPDATE_CHECK_END,
|
||||
APP_UPDATE_CHECK_FOR_UPDATE,
|
||||
APP_UPDATE_CHECK_START,
|
||||
APP_UPDATE_DOWNLOADED,
|
||||
APP_UPDATE_INSTALL,
|
||||
APP_UPDATE_START_DOWNLOAD,
|
||||
COLLAPSE_TO_TRAY_PREFERENCE_KEY,
|
||||
CURRENT_THEME_KEY,
|
||||
DEFAULT_AUTO_UPDATE_PREFERENCE_KEY_SUFFIX,
|
||||
DEFAULT_CHANNEL_PREFERENCE_KEY_SUFFIX,
|
||||
DEFAULT_LIGHT_THEME,
|
||||
DEFAULT_THEME,
|
||||
ENABLE_SYSTEM_NOTIFICATIONS_PREFERENCE_KEY,
|
||||
GET_ADDONS_HIDDEN_COLUMNS_KEY,
|
||||
GET_ADDONS_SORT_ORDER,
|
||||
HORDE_LIGHT_THEME,
|
||||
HORDE_THEME,
|
||||
IPC_APP_CHECK_UPDATE,
|
||||
IPC_APP_INSTALL_UPDATE,
|
||||
IPC_GET_APP_VERSION,
|
||||
LAST_SELECTED_WOW_CLIENT_TYPE_PREFERENCE_KEY,
|
||||
MY_ADDONS_HIDDEN_COLUMNS_KEY,
|
||||
@@ -59,10 +50,6 @@ import { PreferenceStorageService } from "../storage/preference-storage.service"
|
||||
})
|
||||
export class WowUpService {
|
||||
private readonly _preferenceChangeSrc = new Subject<PreferenceChange>();
|
||||
private readonly _wowupUpdateDownloadInProgressSrc = new Subject<boolean>();
|
||||
private readonly _wowupUpdateDownloadedSrc = new Subject<any>();
|
||||
private readonly _wowupUpdateCheckSrc = new Subject<UpdateCheckResult>();
|
||||
private readonly _wowupUpdateCheckInProgressSrc = new Subject<boolean>();
|
||||
|
||||
private _availableVersion = "";
|
||||
|
||||
@@ -73,10 +60,6 @@ export class WowUpService {
|
||||
public readonly applicationUpdaterPath: string = join(this.applicationFolderPath, this.updaterName);
|
||||
|
||||
public readonly preferenceChange$ = this._preferenceChangeSrc.asObservable();
|
||||
public readonly wowupUpdateDownloaded$ = this._wowupUpdateDownloadedSrc.asObservable();
|
||||
public readonly wowupUpdateDownloadInProgress$ = this._wowupUpdateDownloadInProgressSrc.asObservable();
|
||||
public readonly wowupUpdateCheck$ = this._wowupUpdateCheckSrc.asObservable();
|
||||
public readonly wowupUpdateCheckInProgress$ = this._wowupUpdateCheckInProgressSrc.asObservable();
|
||||
|
||||
public constructor(
|
||||
private _preferenceStorageService: PreferenceStorageService,
|
||||
@@ -94,27 +77,6 @@ export class WowUpService {
|
||||
// .then(() => console.debug("createDownloadDirectory complete"))
|
||||
.catch((e) => console.error("Failed to create download directory", e));
|
||||
|
||||
this._electronService.ipcEventReceived$.subscribe((evt) => {
|
||||
switch (evt) {
|
||||
case APP_UPDATE_CHECK_START:
|
||||
console.log(APP_UPDATE_CHECK_START);
|
||||
this._wowupUpdateCheckInProgressSrc.next(true);
|
||||
break;
|
||||
case APP_UPDATE_CHECK_END:
|
||||
console.log(APP_UPDATE_CHECK_END);
|
||||
this._wowupUpdateCheckInProgressSrc.next(false);
|
||||
break;
|
||||
case APP_UPDATE_START_DOWNLOAD:
|
||||
console.log(APP_UPDATE_START_DOWNLOAD);
|
||||
this._wowupUpdateDownloadInProgressSrc.next(true);
|
||||
break;
|
||||
case APP_UPDATE_DOWNLOADED:
|
||||
console.log(APP_UPDATE_DOWNLOADED);
|
||||
this._wowupUpdateDownloadInProgressSrc.next(false);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
this.setAutoStartup()
|
||||
.then(() => console.log("loginItemSettings", this._electronService.getLoginItemSettings()))
|
||||
.catch((e) => console.error(e));
|
||||
@@ -359,17 +321,8 @@ export class WowUpService {
|
||||
await this._fileService.showDirectory(this.applicationLogsFolderPath);
|
||||
}
|
||||
|
||||
public async checkForAppUpdate(): Promise<UpdateCheckResult> {
|
||||
const updateCheckResult: UpdateCheckResult = await this._electronService.invoke(APP_UPDATE_CHECK_FOR_UPDATE);
|
||||
|
||||
// only notify things when the version changes
|
||||
const isSameVersion = await this.isSameVersion(updateCheckResult);
|
||||
if (!isSameVersion) {
|
||||
this._availableVersion = updateCheckResult.updateInfo.version;
|
||||
this._wowupUpdateCheckSrc.next(updateCheckResult);
|
||||
}
|
||||
|
||||
return updateCheckResult;
|
||||
public checkForAppUpdate(): void {
|
||||
this._electronService.send(IPC_APP_CHECK_UPDATE);
|
||||
}
|
||||
|
||||
public async isSameVersion(updateCheckResult: UpdateCheckResult): Promise<boolean> {
|
||||
@@ -377,15 +330,8 @@ export class WowUpService {
|
||||
return updateCheckResult && updateCheckResult.updateInfo?.version === appVersion;
|
||||
}
|
||||
|
||||
public async downloadUpdate(): Promise<any> {
|
||||
const downloadResult = await this._electronService.invoke(APP_UPDATE_START_DOWNLOAD);
|
||||
|
||||
this._wowupUpdateDownloadedSrc.next(downloadResult);
|
||||
return downloadResult;
|
||||
}
|
||||
|
||||
public async installUpdate(): Promise<any> {
|
||||
return await this._electronService.invoke(APP_UPDATE_INSTALL);
|
||||
public installUpdate(): void {
|
||||
return this._electronService.send(IPC_APP_INSTALL_UPDATE);
|
||||
}
|
||||
|
||||
private setDefaultPreference(key: string, defaultValue: any) {
|
||||
|
||||
@@ -70,7 +70,9 @@
|
||||
"SNACKBAR_ACTION": "Update",
|
||||
"SNACKBAR_TEXT": "A new version of WowUp is available",
|
||||
"TOOLTIP": "WowUp update available",
|
||||
"UPDATE_ERROR": "Failed to get WowUp update"
|
||||
"UPDATE_ERROR": "Failed to get WowUp update",
|
||||
"CHECKING_FOR_UPDATE": "Checking for update",
|
||||
"DOWNLOADING_UPDATE": "Downloading update"
|
||||
}
|
||||
},
|
||||
"COMMON": {
|
||||
|
||||
@@ -80,6 +80,9 @@ export const IPC_GET_PENDING_OPEN_URLS = "get-pending-open-urls";
|
||||
export const IPC_GET_LATEST_DIR_UPDATE_TIME = "get-latest-dir-update-time";
|
||||
export const IPC_SYSTEM_PREFERENCES_GET_USER_DEFAULT = "system-preferences-get-user-default";
|
||||
export const IPC_SHOW_OPEN_DIALOG = "show-open-dialog";
|
||||
export const IPC_APP_UPDATE_STATE = "app-update-state";
|
||||
export const IPC_APP_INSTALL_UPDATE = "app-install-update";
|
||||
export const IPC_APP_CHECK_UPDATE = "app-check-update";
|
||||
|
||||
// IPC STORAGE
|
||||
export const IPC_STORE_GET_OBJECT = "store-get-object";
|
||||
@@ -115,17 +118,6 @@ export const SELECTED_DETAILS_TAB_KEY = "selected_details_tab";
|
||||
export const ADDON_MIGRATION_VERSION_KEY = "addon_migration_version";
|
||||
export const UPDATE_NOTES_POPUP_VERSION_KEY = "update_notes_popup_version";
|
||||
|
||||
// APP UPDATER
|
||||
export const APP_UPDATE_ERROR = "app-update-error";
|
||||
export const APP_UPDATE_DOWNLOADED = "app-update-downloaded";
|
||||
export const APP_UPDATE_NOT_AVAILABLE = "app-update-not-available";
|
||||
export const APP_UPDATE_AVAILABLE = "app-update-available";
|
||||
export const APP_UPDATE_START_DOWNLOAD = "app-update-start-download";
|
||||
export const APP_UPDATE_INSTALL = "app-update-install";
|
||||
export const APP_UPDATE_CHECK_FOR_UPDATE = "app-update-check-for-update";
|
||||
export const APP_UPDATE_CHECK_START = "app-update-check-start";
|
||||
export const APP_UPDATE_CHECK_END = "app-update-check-end";
|
||||
|
||||
// THEMES
|
||||
export const DEFAULT_THEME = "default-theme";
|
||||
export const DEFAULT_LIGHT_THEME = "default-theme-light-theme";
|
||||
|
||||
6
wowup-electron/src/common/wowup.d.ts
vendored
6
wowup-electron/src/common/wowup.d.ts
vendored
@@ -17,7 +17,8 @@ declare type MainChannels =
|
||||
| "power-monitor-lock"
|
||||
| "power-monitor-unlock"
|
||||
| "request-install-from-url"
|
||||
| "custom-protocol-received";
|
||||
| "custom-protocol-received"
|
||||
| "app-update-state";
|
||||
|
||||
// Events that can be sent from renderer to main
|
||||
declare type RendererChannels =
|
||||
@@ -68,7 +69,8 @@ declare type RendererChannels =
|
||||
| "store-set-object"
|
||||
| "get-latest-dir-update-time"
|
||||
| "system-preferences-get-user-default"
|
||||
| "show-open-dialog";
|
||||
| "show-open-dialog"
|
||||
| "app-install-update";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
||||
@@ -11,6 +11,28 @@ export enum AddonDependencyType {
|
||||
Other = 4,
|
||||
}
|
||||
|
||||
export enum AppUpdateState {
|
||||
CheckingForUpdate = 1,
|
||||
UpdateAvailable,
|
||||
UpdateNotAvailable,
|
||||
Downloading,
|
||||
Downloaded,
|
||||
Error,
|
||||
}
|
||||
|
||||
export interface AppUpdateEvent {
|
||||
state: AppUpdateState;
|
||||
progress?: AppUpdateDownloadProgress;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export interface AppUpdateDownloadProgress {
|
||||
bytesPerSecond: number;
|
||||
percent: number;
|
||||
transferred: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export enum AddonWarningType {
|
||||
MissingOnProvider = "missing-on-provider",
|
||||
NoProviderFiles = "no-provider-files",
|
||||
|
||||
Reference in New Issue
Block a user