mirror of
https://github.com/upscayl/upscayl.git
synced 2026-04-03 03:00:13 -04:00
Initial refactor
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
const COMMAND = {
|
||||
const ELECTRON_COMMANDS = {
|
||||
SELECT_FILE: "Select a File",
|
||||
SELECT_FOLDER: "Select a Folder",
|
||||
UPSCAYL: "Upscale the Image",
|
||||
@@ -27,4 +27,4 @@ const COMMAND = {
|
||||
UPSCAYL_ERROR: "Upscaling Error",
|
||||
};
|
||||
|
||||
export default COMMAND;
|
||||
export default ELECTRON_COMMANDS;
|
||||
|
||||
@@ -3,7 +3,7 @@ type FeatureFlags = {
|
||||
SHOW_UPSCAYL_CLOUD_INFO: boolean;
|
||||
};
|
||||
|
||||
export const featureFlags: FeatureFlags = {
|
||||
export const FEATURE_FLAGS: FeatureFlags = {
|
||||
APP_STORE_BUILD: false,
|
||||
SHOW_UPSCAYL_CLOUD_INFO: false,
|
||||
};
|
||||
|
||||
@@ -11,7 +11,7 @@ import { spawnUpscayl } from "../utils/spawn-upscayl";
|
||||
import { getBatchArguments } from "../utils/get-arguments";
|
||||
import slash from "../utils/slash";
|
||||
import { modelsPath } from "../utils/get-resource-paths";
|
||||
import COMMAND from "../../common/commands";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import { BatchUpscaylPayload } from "../../common/types/types";
|
||||
import showNotification from "../utils/show-notification";
|
||||
import { DEFAULT_MODELS } from "../../common/models-list";
|
||||
@@ -72,28 +72,28 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
if (!mainWindow) return;
|
||||
data = data.toString();
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_PROGRESS,
|
||||
ELECTRON_COMMANDS.FOLDER_UPSCAYL_PROGRESS,
|
||||
data.toString(),
|
||||
);
|
||||
if ((data as string).includes("Error")) {
|
||||
logit("❌ ", data);
|
||||
encounteredError = true;
|
||||
} else if (data.includes("Resizing")) {
|
||||
mainWindow.webContents.send(COMMAND.SCALING_AND_CONVERTING);
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.SCALING_AND_CONVERTING);
|
||||
}
|
||||
};
|
||||
const onError = (data: any) => {
|
||||
if (!mainWindow) return;
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_PROGRESS,
|
||||
ELECTRON_COMMANDS.FOLDER_UPSCAYL_PROGRESS,
|
||||
data.toString(),
|
||||
);
|
||||
failed = true;
|
||||
upscayl.kill();
|
||||
mainWindow &&
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
ELECTRON_COMMANDS.UPSCAYL_ERROR,
|
||||
`Error upscaling images! ${data}`,
|
||||
);
|
||||
return;
|
||||
@@ -104,7 +104,7 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
logit("💯 Done upscaling");
|
||||
upscayl.kill();
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_DONE,
|
||||
ELECTRON_COMMANDS.FOLDER_UPSCAYL_DONE,
|
||||
outputFolderPath,
|
||||
);
|
||||
if (!encounteredError) {
|
||||
|
||||
@@ -5,11 +5,11 @@ import {
|
||||
} from "../utils/config-variables";
|
||||
import logit from "../utils/logit";
|
||||
import slash from "../utils/slash";
|
||||
import COMMAND from "../../common/commands";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import getModels from "../utils/get-models";
|
||||
import { getMainWindow } from "../main-window";
|
||||
import settings from "electron-settings";
|
||||
import { featureFlags } from "../../common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "../../common/feature-flags";
|
||||
|
||||
const customModelsSelect = async (event, message) => {
|
||||
const mainWindow = getMainWindow();
|
||||
@@ -27,7 +27,7 @@ const customModelsSelect = async (event, message) => {
|
||||
message: "Select Custom Models Folder that is named 'models'",
|
||||
});
|
||||
|
||||
if (featureFlags.APP_STORE_BUILD && bookmarks && bookmarks.length > 0) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD && bookmarks && bookmarks.length > 0) {
|
||||
console.log("🚨 Setting Bookmark: ", bookmarks);
|
||||
await settings.set("custom-models-bookmarks", bookmarks[0]);
|
||||
}
|
||||
@@ -55,7 +55,10 @@ const customModelsSelect = async (event, message) => {
|
||||
}
|
||||
|
||||
const models = await getModels(savedCustomModelsPath);
|
||||
mainWindow.webContents.send(COMMAND.CUSTOM_MODEL_FILES_LIST, models);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.CUSTOM_MODEL_FILES_LIST,
|
||||
models,
|
||||
);
|
||||
|
||||
logit("📁 Custom Folder Path: ", savedCustomModelsPath);
|
||||
return savedCustomModelsPath;
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from "../utils/get-arguments";
|
||||
import { modelsPath } from "../utils/get-resource-paths";
|
||||
import logit from "../utils/logit";
|
||||
import COMMAND from "../../common/commands";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import { DoubleUpscaylPayload } from "../../common/types/types";
|
||||
import { ImageFormat } from "../types/types";
|
||||
import showNotification from "../utils/show-notification";
|
||||
@@ -87,12 +87,15 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
if (!mainWindow) return;
|
||||
data.toString();
|
||||
// SEND UPSCAYL PROGRESS TO RENDERER
|
||||
mainWindow.webContents.send(COMMAND.DOUBLE_UPSCAYL_PROGRESS, data);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_PROGRESS,
|
||||
data,
|
||||
);
|
||||
// SET FAILED TO TRUE
|
||||
failed2 = true;
|
||||
mainWindow &&
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
ELECTRON_COMMANDS.UPSCAYL_ERROR,
|
||||
"Error upscaling image. Error: " + data,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
@@ -105,13 +108,16 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
// CONVERT DATA TO STRING
|
||||
data = data.toString();
|
||||
// SEND UPSCAYL PROGRESS TO RENDERER
|
||||
mainWindow.webContents.send(COMMAND.DOUBLE_UPSCAYL_PROGRESS, data);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_PROGRESS,
|
||||
data,
|
||||
);
|
||||
// IF PROGRESS HAS ERROR, UPSCAYL FAILED
|
||||
if (data.includes("Error")) {
|
||||
upscayl2.kill();
|
||||
failed2 = true;
|
||||
} else if (data.includes("Resizing")) {
|
||||
mainWindow.webContents.send(COMMAND.SCALING_AND_CONVERTING);
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.SCALING_AND_CONVERTING);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -121,7 +127,10 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
logit("💯 Done upscaling");
|
||||
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(COMMAND.DOUBLE_UPSCAYL_DONE, outFile);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_DONE,
|
||||
outFile,
|
||||
);
|
||||
showNotification("Upscayled", "Image upscayled successfully!");
|
||||
}
|
||||
};
|
||||
@@ -132,12 +141,15 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
mainWindow.setProgressBar(-1);
|
||||
data.toString();
|
||||
// SEND UPSCAYL PROGRESS TO RENDERER
|
||||
mainWindow.webContents.send(COMMAND.DOUBLE_UPSCAYL_PROGRESS, data);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_PROGRESS,
|
||||
data,
|
||||
);
|
||||
// SET FAILED TO TRUE
|
||||
failed = true;
|
||||
mainWindow &&
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
ELECTRON_COMMANDS.UPSCAYL_ERROR,
|
||||
"Error upscaling image. Error: " + data,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
@@ -150,13 +162,16 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
// CONVERT DATA TO STRING
|
||||
data = data.toString();
|
||||
// SEND UPSCAYL PROGRESS TO RENDERER
|
||||
mainWindow.webContents.send(COMMAND.DOUBLE_UPSCAYL_PROGRESS, data);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_PROGRESS,
|
||||
data,
|
||||
);
|
||||
// IF PROGRESS HAS ERROR, UPSCAYL FAILED
|
||||
if (data.includes("Error") || data.includes("failed")) {
|
||||
upscayl.kill();
|
||||
failed = true;
|
||||
} else if (data.includes("Resizing")) {
|
||||
mainWindow.webContents.send(COMMAND.SCALING_AND_CONVERTING);
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.SCALING_AND_CONVERTING);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import COMMAND from "../../common/commands";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import { getMainWindow } from "../main-window";
|
||||
import {
|
||||
savedCustomModelsPath,
|
||||
@@ -17,7 +17,10 @@ const getModelsList = async (event, payload) => {
|
||||
logit("📁 Custom Models Folder Path: ", savedCustomModelsPath);
|
||||
const models = await getModels(payload);
|
||||
|
||||
mainWindow.webContents.send(COMMAND.CUSTOM_MODEL_FILES_LIST, models);
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.CUSTOM_MODEL_FILES_LIST,
|
||||
models,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import fs from "fs";
|
||||
import { modelsPath } from "../utils/get-resource-paths";
|
||||
import COMMAND from "../../common/commands";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import {
|
||||
savedCustomModelsPath,
|
||||
setChildProcesses,
|
||||
@@ -60,14 +60,17 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
// Check if windows can write the new filename to the file system
|
||||
if (outFile.length >= 255) {
|
||||
logit("Filename too long for Windows.");
|
||||
mainWindow.webContents.send(COMMAND.UPSCAYL_ERROR, "The filename exceeds the maximum path length allowed by Windows. Please shorten the filename or choose a different save location.");
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.UPSCAYL_ERROR,
|
||||
"The filename exceeds the maximum path length allowed by Windows. Please shorten the filename or choose a different save location.",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// UPSCALE
|
||||
if (fs.existsSync(outFile) && !overwrite) {
|
||||
// If already upscayled, just output that file
|
||||
logit("✅ Already upscayled at: ", outFile);
|
||||
mainWindow.webContents.send(COMMAND.UPSCAYL_DONE, outFile);
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.UPSCAYL_DONE, outFile);
|
||||
} else {
|
||||
logit(
|
||||
"✅ Upscayl Variables: ",
|
||||
@@ -115,18 +118,24 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
logit(data.toString());
|
||||
mainWindow.setProgressBar(parseFloat(data.slice(0, data.length)) / 100);
|
||||
data = data.toString();
|
||||
mainWindow.webContents.send(COMMAND.UPSCAYL_PROGRESS, data.toString());
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.UPSCAYL_PROGRESS,
|
||||
data.toString(),
|
||||
);
|
||||
if (data.includes("Error")) {
|
||||
upscayl.kill();
|
||||
failed = true;
|
||||
} else if (data.includes("Resizing")) {
|
||||
mainWindow.webContents.send(COMMAND.SCALING_AND_CONVERTING);
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.SCALING_AND_CONVERTING);
|
||||
}
|
||||
};
|
||||
const onError = (data) => {
|
||||
if (!mainWindow) return;
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(COMMAND.UPSCAYL_ERROR, data.toString());
|
||||
mainWindow.webContents.send(
|
||||
ELECTRON_COMMANDS.UPSCAYL_ERROR,
|
||||
data.toString(),
|
||||
);
|
||||
failed = true;
|
||||
upscayl.kill();
|
||||
return;
|
||||
@@ -137,7 +146,7 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
// Free up memory
|
||||
upscayl.kill();
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(COMMAND.UPSCAYL_DONE, outFile);
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.UPSCAYL_DONE, outFile);
|
||||
showNotification("Upscayl", "Image upscayled successfully!");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ import { getMainWindow } from "../main-window";
|
||||
import { savedImagePath, setSavedImagePath } from "../utils/config-variables";
|
||||
import logit from "../utils/logit";
|
||||
import settings from "electron-settings";
|
||||
import { featureFlags } from "../../common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "../../common/feature-flags";
|
||||
|
||||
const selectFile = async () => {
|
||||
const mainWindow = getMainWindow();
|
||||
@@ -33,7 +33,7 @@ const selectFile = async () => {
|
||||
],
|
||||
});
|
||||
|
||||
if (featureFlags.APP_STORE_BUILD && bookmarks && bookmarks.length > 0) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD && bookmarks && bookmarks.length > 0) {
|
||||
console.log("🚨 Setting Bookmark: ", bookmarks);
|
||||
settings.set("file-bookmarks", bookmarks[0]);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,12 @@ import {
|
||||
} from "../utils/config-variables";
|
||||
import logit from "../utils/logit";
|
||||
import settings from "electron-settings";
|
||||
import { featureFlags } from "../../common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "../../common/feature-flags";
|
||||
|
||||
const selectFolder = async (event, message) => {
|
||||
let closeAccess;
|
||||
const folderBookmarks = await settings.get("folder-bookmarks");
|
||||
if (featureFlags.APP_STORE_BUILD && folderBookmarks) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD && folderBookmarks) {
|
||||
logit("🚨 Folder Bookmarks: ", folderBookmarks);
|
||||
try {
|
||||
closeAccess = app.startAccessingSecurityScopedResource(
|
||||
@@ -31,7 +31,7 @@ const selectFolder = async (event, message) => {
|
||||
securityScopedBookmarks: true,
|
||||
});
|
||||
|
||||
if (featureFlags.APP_STORE_BUILD && bookmarks && bookmarks.length > 0) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD && bookmarks && bookmarks.length > 0) {
|
||||
console.log("🚨 Setting folder Bookmark: ", bookmarks);
|
||||
await settings.set("folder-bookmarks", bookmarks[0]);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import prepareNext from "electron-next";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import log from "electron-log";
|
||||
import { app, ipcMain, protocol } from "electron";
|
||||
import COMMAND from "../common/commands";
|
||||
import ELECTRON_COMMANDS from "../common/commands";
|
||||
import logit from "./utils/logit";
|
||||
import openFolder from "./commands/open-folder";
|
||||
import stop from "./commands/stop";
|
||||
@@ -17,7 +17,7 @@ import { execPath, modelsPath } from "./utils/get-resource-paths";
|
||||
import batchUpscayl from "./commands/batch-upscayl";
|
||||
import doubleUpscayl from "./commands/double-upscayl";
|
||||
import autoUpdate from "./commands/auto-update";
|
||||
import { featureFlags } from "../common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "../common/feature-flags";
|
||||
import settings from "electron-settings";
|
||||
|
||||
// INITIALIZATION
|
||||
@@ -43,14 +43,14 @@ app.on("ready", async () => {
|
||||
log.info(
|
||||
"🆙 Upscayl version:",
|
||||
app.getVersion(),
|
||||
featureFlags.APP_STORE_BUILD && "MAC-APP-STORE",
|
||||
FEATURE_FLAGS.APP_STORE_BUILD && "MAC-APP-STORE",
|
||||
);
|
||||
log.info("🚀 UPSCAYL EXEC PATH: ", execPath);
|
||||
log.info("🚀 MODELS PATH: ", modelsPath);
|
||||
|
||||
let closeAccess;
|
||||
const folderBookmarks = await settings.get("folder-bookmarks");
|
||||
if (featureFlags.APP_STORE_BUILD && folderBookmarks) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD && folderBookmarks) {
|
||||
logit("🚨 Folder Bookmarks: ", folderBookmarks);
|
||||
try {
|
||||
closeAccess = app.startAccessingSecurityScopedResource(
|
||||
@@ -68,29 +68,32 @@ app.on("window-all-closed", () => {
|
||||
});
|
||||
|
||||
// ! ENABLE THIS FOR MACOS APP STORE BUILD
|
||||
if (featureFlags.APP_STORE_BUILD) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD) {
|
||||
logit("🚀 APP STORE BUILD ENABLED");
|
||||
app.commandLine.appendSwitch("in-process-gpu");
|
||||
}
|
||||
|
||||
ipcMain.on(COMMAND.STOP, stop);
|
||||
ipcMain.on(ELECTRON_COMMANDS.STOP, stop);
|
||||
|
||||
ipcMain.on(COMMAND.OPEN_FOLDER, openFolder);
|
||||
ipcMain.on(ELECTRON_COMMANDS.OPEN_FOLDER, openFolder);
|
||||
|
||||
ipcMain.handle(COMMAND.SELECT_FOLDER, selectFolder);
|
||||
ipcMain.handle(ELECTRON_COMMANDS.SELECT_FOLDER, selectFolder);
|
||||
|
||||
ipcMain.handle(COMMAND.SELECT_FILE, selectFile);
|
||||
ipcMain.handle(ELECTRON_COMMANDS.SELECT_FILE, selectFile);
|
||||
|
||||
ipcMain.on(COMMAND.GET_MODELS_LIST, getModelsList);
|
||||
ipcMain.on(ELECTRON_COMMANDS.GET_MODELS_LIST, getModelsList);
|
||||
|
||||
ipcMain.handle(COMMAND.SELECT_CUSTOM_MODEL_FOLDER, customModelsSelect);
|
||||
ipcMain.handle(
|
||||
ELECTRON_COMMANDS.SELECT_CUSTOM_MODEL_FOLDER,
|
||||
customModelsSelect,
|
||||
);
|
||||
|
||||
ipcMain.on(COMMAND.UPSCAYL, imageUpscayl);
|
||||
ipcMain.on(ELECTRON_COMMANDS.UPSCAYL, imageUpscayl);
|
||||
|
||||
ipcMain.on(COMMAND.FOLDER_UPSCAYL, batchUpscayl);
|
||||
ipcMain.on(ELECTRON_COMMANDS.FOLDER_UPSCAYL, batchUpscayl);
|
||||
|
||||
ipcMain.on(COMMAND.DOUBLE_UPSCAYL, doubleUpscayl);
|
||||
ipcMain.on(ELECTRON_COMMANDS.DOUBLE_UPSCAYL, doubleUpscayl);
|
||||
|
||||
if (!featureFlags.APP_STORE_BUILD) {
|
||||
if (!FEATURE_FLAGS.APP_STORE_BUILD) {
|
||||
autoUpdater.on("update-downloaded", autoUpdate);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { BrowserWindow, shell } from "electron";
|
||||
import { getPlatform } from "./utils/get-device-specs";
|
||||
import { join } from "path";
|
||||
import COMMAND from "../common/commands";
|
||||
import ELECTRON_COMMANDS from "../common/commands";
|
||||
import { fetchLocalStorage } from "./utils/config-variables";
|
||||
import electronIsDev from "electron-is-dev";
|
||||
import { format } from "url";
|
||||
@@ -49,7 +49,7 @@ const createMainWindow = () => {
|
||||
|
||||
fetchLocalStorage();
|
||||
|
||||
mainWindow.webContents.send(COMMAND.OS, getPlatform());
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.OS, getPlatform());
|
||||
|
||||
mainWindow.setMenuBarVisibility(false);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "fs";
|
||||
import logit from "./logit";
|
||||
import { MessageBoxOptions, app, dialog } from "electron";
|
||||
import settings from "electron-settings";
|
||||
import { featureFlags } from "../../common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "../../common/feature-flags";
|
||||
|
||||
const getModels = async (folderPath: string | undefined) => {
|
||||
let models: string[] = [];
|
||||
@@ -11,14 +11,14 @@ const getModels = async (folderPath: string | undefined) => {
|
||||
// SECURITY SCOPED BOOKMARKS
|
||||
let closeAccess;
|
||||
const customModelsBookmarks = await settings.get("custom-models-bookmarks");
|
||||
if (featureFlags.APP_STORE_BUILD && customModelsBookmarks) {
|
||||
if (FEATURE_FLAGS.APP_STORE_BUILD && customModelsBookmarks) {
|
||||
console.log(
|
||||
"🚀 => file: get-models.ts:18 => customModelsBookmarks:",
|
||||
customModelsBookmarks
|
||||
customModelsBookmarks,
|
||||
);
|
||||
try {
|
||||
closeAccess = app.startAccessingSecurityScopedResource(
|
||||
customModelsBookmarks as string
|
||||
customModelsBookmarks as string,
|
||||
);
|
||||
} catch (error) {
|
||||
logit("📁 Custom Models Bookmarks Error: ", error);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import log from "electron-log";
|
||||
import COMMAND from "../../common/commands";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import { getMainWindow } from "../main-window";
|
||||
|
||||
const logit = (...args: any) => {
|
||||
@@ -9,7 +9,7 @@ const logit = (...args: any) => {
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
return;
|
||||
}
|
||||
mainWindow.webContents.send(COMMAND.LOG, args.join(" "));
|
||||
mainWindow.webContents.send(ELECTRON_COMMANDS.LOG, args.join(" "));
|
||||
};
|
||||
|
||||
export default logit;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { featureFlags } from "@common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "@common/feature-flags";
|
||||
import React from "react";
|
||||
import Logo from "./icons/Logo";
|
||||
import { useAtomValue } from "jotai";
|
||||
@@ -21,7 +21,7 @@ export default function Header({ version }: { version: string }) {
|
||||
<h1 className="text-3xl font-bold">
|
||||
{t("TITLE")}{" "}
|
||||
<span className="text-xs">
|
||||
{version} {featureFlags.APP_STORE_BUILD && "Mac"}
|
||||
{version} {FEATURE_FLAGS.APP_STORE_BUILD && "Mac"}
|
||||
</span>
|
||||
</h1>
|
||||
<p className="">{t("HEADER.DESCRIPTION")}</p>
|
||||
|
||||
20
renderer/components/hooks/use-electron.ts
Normal file
20
renderer/components/hooks/use-electron.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { useEffect } from "react";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { translationAtom } from "@/atoms/translations-atom";
|
||||
import ELECTRON_COMMANDS from "@common/commands";
|
||||
import useLog from "./useLog";
|
||||
|
||||
const useElectron = ({
|
||||
command,
|
||||
func,
|
||||
}: {
|
||||
command: (typeof ELECTRON_COMMANDS)[keyof typeof ELECTRON_COMMANDS];
|
||||
func: (...args: any[]) => void;
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
window.electron.on(command, func);
|
||||
return () => {
|
||||
window.electron.off(command, func);
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
16
renderer/components/hooks/use-upscayl-version.ts
Normal file
16
renderer/components/hooks/use-upscayl-version.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const useUpscaylVersion = () => {
|
||||
const [version, setVersion] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const upscaylVersion = navigator?.userAgent?.match(
|
||||
/Upscayl\/([\d\.]+\d+)/,
|
||||
)?.[1];
|
||||
setVersion(upscaylVersion);
|
||||
}, []);
|
||||
|
||||
return version;
|
||||
};
|
||||
|
||||
export default useUpscaylVersion;
|
||||
399
renderer/components/main-content/index.tsx
Normal file
399
renderer/components/main-content/index.tsx
Normal file
@@ -0,0 +1,399 @@
|
||||
import useLog from "../hooks/useLog";
|
||||
import { useState, useCallback, useMemo, useRef } from "react";
|
||||
import ELECTRON_COMMANDS from "../../../common/commands";
|
||||
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { logAtom } from "../../atoms/logAtom";
|
||||
import { modelsListAtom } from "../../atoms/modelsListAtom";
|
||||
import {
|
||||
batchModeAtom,
|
||||
lensSizeAtom,
|
||||
compressionAtom,
|
||||
dontShowCloudModalAtom,
|
||||
noImageProcessingAtom,
|
||||
savedOutputPathAtom,
|
||||
progressAtom,
|
||||
scaleAtom,
|
||||
viewTypeAtom,
|
||||
rememberOutputFolderAtom,
|
||||
customWidthAtom,
|
||||
useCustomWidthAtom,
|
||||
tileSizeAtom,
|
||||
showSidebarAtom,
|
||||
} from "../../atoms/userSettingsAtom";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { sanitizePath } from "@common/sanitize-path";
|
||||
import { translationAtom } from "@/atoms/translations-atom";
|
||||
import getDirectoryFromPath from "@common/get-directory-from-path";
|
||||
import { FEATURE_FLAGS } from "@common/feature-flags";
|
||||
import { VALID_IMAGE_FORMATS } from "@/lib/valid-formats";
|
||||
import ProgressBar from "../upscayl-tab/view/ProgressBar";
|
||||
import RightPaneInfo from "../upscayl-tab/view/RightPaneInfo";
|
||||
import ImageOptions from "../upscayl-tab/view/ImageOptions";
|
||||
import { ReactCompareSlider } from "react-compare-slider";
|
||||
import useUpscaylVersion from "../hooks/use-upscayl-version";
|
||||
("use client");
|
||||
|
||||
const MainContent = ({
|
||||
imagePath,
|
||||
resetImagePaths,
|
||||
upscaledBatchFolderPath,
|
||||
setImagePath,
|
||||
validateImagePath,
|
||||
selectFolderHandler,
|
||||
selectImageHandler,
|
||||
upscaledImagePath,
|
||||
batchFolderPath,
|
||||
doubleUpscaylCounter,
|
||||
setDimensions,
|
||||
}) => {
|
||||
const t = useAtomValue(translationAtom);
|
||||
const { logit } = useLog();
|
||||
const { toast } = useToast();
|
||||
|
||||
const upscaledImageRef = useRef<HTMLImageElement>(null);
|
||||
|
||||
const [backgroundPosition, setBackgroundPosition] = useState("0% 0%");
|
||||
const [lensPosition, setLensPosition] = useState({ x: 0, y: 0 });
|
||||
|
||||
const setOutputPath = useSetAtom(savedOutputPathAtom);
|
||||
const progress = useAtomValue(progressAtom);
|
||||
const batchMode = useAtomValue(batchModeAtom);
|
||||
|
||||
const viewType = useAtomValue(viewTypeAtom);
|
||||
const lensSize = useAtomValue(lensSizeAtom);
|
||||
const rememberOutputFolder = useAtomValue(rememberOutputFolderAtom);
|
||||
const [zoomAmount, setZoomAmount] = useState("100");
|
||||
const version = useUpscaylVersion();
|
||||
|
||||
const sanitizedUpscaledImagePath = useMemo(
|
||||
() => sanitizePath(upscaledImagePath),
|
||||
[upscaledImagePath],
|
||||
);
|
||||
|
||||
// DRAG AND DROP HANDLERS
|
||||
const handleDragEnter = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("drag enter");
|
||||
};
|
||||
const handleDragLeave = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("drag leave");
|
||||
};
|
||||
const handleDragOver = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("drag over");
|
||||
};
|
||||
|
||||
const openFolderHandler = (e) => {
|
||||
const { logit } = useLog();
|
||||
logit("📂 OPEN_FOLDER: ", upscaledBatchFolderPath);
|
||||
window.electron.send(
|
||||
ELECTRON_COMMANDS.OPEN_FOLDER,
|
||||
upscaledBatchFolderPath,
|
||||
);
|
||||
};
|
||||
|
||||
const sanitizedImagePath = useMemo(
|
||||
() => sanitizePath(imagePath),
|
||||
[imagePath],
|
||||
);
|
||||
|
||||
const handleDrop = (e) => {
|
||||
e.preventDefault();
|
||||
resetImagePaths();
|
||||
if (
|
||||
e.dataTransfer.items.length === 0 ||
|
||||
e.dataTransfer.files.length === 0
|
||||
) {
|
||||
logit("👎 No valid files dropped");
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const type = e.dataTransfer.items[0].type;
|
||||
const filePath = e.dataTransfer.files[0].path;
|
||||
const extension = e.dataTransfer.files[0].name.split(".").at(-1);
|
||||
logit("⤵️ Dropped file: ", JSON.stringify({ type, filePath, extension }));
|
||||
if (
|
||||
!type.includes("image") ||
|
||||
!VALID_IMAGE_FORMATS.includes(extension.toLowerCase())
|
||||
) {
|
||||
logit("🚫 Invalid file dropped");
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
|
||||
});
|
||||
} else {
|
||||
logit("🖼 Setting image path: ", filePath);
|
||||
setImagePath(filePath);
|
||||
var dirname = getDirectoryFromPath(filePath);
|
||||
logit("🗂 Setting output path: ", dirname);
|
||||
if (!FEATURE_FLAGS.APP_STORE_BUILD) {
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
}
|
||||
validateImagePath(filePath);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePaste = (e) => {
|
||||
resetImagePaths();
|
||||
e.preventDefault();
|
||||
const type = e.clipboardData.items[0].type;
|
||||
const filePath = e.clipboardData.files[0].path;
|
||||
const extension = e.clipboardData.files[0].name.split(".").at(-1);
|
||||
logit("📋 Pasted file: ", JSON.stringify({ type, filePath, extension }));
|
||||
if (
|
||||
!type.includes("image") &&
|
||||
!VALID_IMAGE_FORMATS.includes(extension.toLowerCase())
|
||||
) {
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
|
||||
});
|
||||
} else {
|
||||
setImagePath(filePath);
|
||||
var dirname = getDirectoryFromPath(filePath);
|
||||
logit("🗂 Setting output path: ", dirname);
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseMove = useCallback((e: any) => {
|
||||
const { left, top, width, height } = e.target.getBoundingClientRect();
|
||||
const x = ((e.pageX - left) / width) * 100;
|
||||
const y = ((e.pageY - top) / height) * 100;
|
||||
setBackgroundPosition(`${x}% ${y}%`);
|
||||
}, []);
|
||||
|
||||
const handleMouseMoveCompare = (e: React.MouseEvent) => {
|
||||
if (upscaledImageRef.current) {
|
||||
const { left, top, width, height } =
|
||||
upscaledImageRef.current.getBoundingClientRect();
|
||||
const x = e.clientX - left;
|
||||
const y = e.clientY - top;
|
||||
setLensPosition({
|
||||
x: Math.max(0, Math.min(x - lensSize, width - lensSize * 2)),
|
||||
y: Math.max(0, Math.min(y - lensSize / 2, height - lensSize)),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const stopHandler = () => {
|
||||
window.electron.send(ELECTRON_COMMANDS.STOP);
|
||||
logit("🛑 Stopping Upscayl");
|
||||
resetImagePaths();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className="relative flex h-screen w-full flex-col items-center justify-center"
|
||||
onDrop={(e) => handleDrop(e)}
|
||||
onDragOver={(e) => handleDragOver(e)}
|
||||
onDragEnter={(e) => handleDragEnter(e)}
|
||||
onDragLeave={(e) => handleDragLeave(e)}
|
||||
onDoubleClick={() => {
|
||||
if (batchMode) {
|
||||
selectFolderHandler();
|
||||
} else {
|
||||
selectImageHandler();
|
||||
}
|
||||
}}
|
||||
onPaste={(e) => handlePaste(e)}
|
||||
>
|
||||
{window.electron.platform === "mac" && (
|
||||
<div className="mac-titlebar absolute top-0 h-8 w-full"></div>
|
||||
)}
|
||||
{progress.length > 0 &&
|
||||
upscaledImagePath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0 ? (
|
||||
<ProgressBar
|
||||
batchMode={batchMode}
|
||||
progress={progress}
|
||||
doubleUpscaylCounter={doubleUpscaylCounter}
|
||||
stopHandler={stopHandler}
|
||||
/>
|
||||
) : null}
|
||||
{/* DEFAULT PANE INFO */}
|
||||
{((!batchMode &&
|
||||
imagePath.length === 0 &&
|
||||
upscaledImagePath.length === 0) ||
|
||||
(batchMode &&
|
||||
batchFolderPath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0)) && (
|
||||
<RightPaneInfo version={version} batchMode={batchMode} />
|
||||
)}
|
||||
{/* SHOW SELECTED IMAGE */}
|
||||
{!batchMode && upscaledImagePath.length === 0 && imagePath.length > 0 && (
|
||||
<>
|
||||
<ImageOptions
|
||||
zoomAmount={zoomAmount}
|
||||
setZoomAmount={setZoomAmount}
|
||||
resetImagePaths={resetImagePaths}
|
||||
hideZoomOptions={true}
|
||||
/>
|
||||
<img
|
||||
src={"file:///" + sanitizePath(imagePath)}
|
||||
onLoad={(e: any) => {
|
||||
setDimensions({
|
||||
width: e.target.naturalWidth,
|
||||
height: e.target.naturalHeight,
|
||||
});
|
||||
}}
|
||||
draggable="false"
|
||||
alt=""
|
||||
className="h-full w-full bg-gradient-to-br from-base-300 to-base-100 object-contain"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* BATCH UPSCALE SHOW SELECTED FOLDER */}
|
||||
{batchMode &&
|
||||
upscaledBatchFolderPath.length === 0 &&
|
||||
batchFolderPath.length > 0 && (
|
||||
<p className="select-none text-base-content">
|
||||
<span className="font-bold">
|
||||
{t("APP.PROGRESS.BATCH.SELECTED_FOLDER_TITLE")}
|
||||
</span>{" "}
|
||||
{batchFolderPath}
|
||||
</p>
|
||||
)}
|
||||
{/* BATCH UPSCALE DONE INFO */}
|
||||
{batchMode && upscaledBatchFolderPath.length > 0 && (
|
||||
<div className="z-50 flex flex-col items-center">
|
||||
<p className="select-none py-4 font-bold text-base-content">
|
||||
{t("APP.PROGRESS.BATCH.DONE_TITLE")}
|
||||
</p>
|
||||
<button
|
||||
className="bg-gradient-blue btn btn-primary rounded-btn p-3 font-medium text-white/90 transition-colors"
|
||||
onClick={openFolderHandler}
|
||||
>
|
||||
{t("APP.PROGRESS.BATCH.OPEN_UPSCAYLED_FOLDER_TITLE")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<ImageOptions
|
||||
zoomAmount={zoomAmount}
|
||||
setZoomAmount={setZoomAmount}
|
||||
resetImagePaths={resetImagePaths}
|
||||
/>
|
||||
{!batchMode && viewType === "lens" && upscaledImagePath && imagePath && (
|
||||
<div
|
||||
className="group relative h-full w-full overflow-hidden"
|
||||
onMouseMove={handleMouseMoveCompare}
|
||||
>
|
||||
{/* UPSCALED IMAGE */}
|
||||
<img
|
||||
className="h-full w-full object-contain"
|
||||
src={"file:///" + sanitizedUpscaledImagePath}
|
||||
alt="Upscaled"
|
||||
ref={upscaledImageRef}
|
||||
/>
|
||||
{/* LENS */}
|
||||
<div
|
||||
className="pointer-events-none absolute opacity-0 transition-opacity before:absolute before:left-1/2 before:h-full before:w-[2px] before:bg-white group-hover:opacity-100"
|
||||
style={{
|
||||
left: `${lensPosition.x}px`,
|
||||
top: `${lensPosition.y}px`,
|
||||
width: lensSize * 2,
|
||||
height: lensSize,
|
||||
border: "2px solid white",
|
||||
boxShadow: "0 0 0 9999px rgba(0, 0, 0, 0.5)",
|
||||
}}
|
||||
>
|
||||
<div className="flex h-full w-full">
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<img
|
||||
src={"file:///" + sanitizedImagePath}
|
||||
alt="Original"
|
||||
className="h-full w-full"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
objectPosition: `${-lensPosition.x}px ${-lensPosition.y}px`,
|
||||
transform: `scale(${parseInt(zoomAmount) / 100})`,
|
||||
transformOrigin: "top left",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<img
|
||||
src={"file:///" + sanitizedUpscaledImagePath}
|
||||
alt="Upscaled"
|
||||
className="h-full w-full"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
objectPosition: `${-lensPosition.x}px ${-lensPosition.y}px`,
|
||||
transform: `scale(${parseInt(zoomAmount) / 100})`,
|
||||
transformOrigin: "top left",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 flex w-full items-center justify-around bg-black bg-opacity-50 p-1 px-2 text-center text-xs text-white backdrop-blur-sm">
|
||||
<span>Original</span>
|
||||
<span>Upscayl</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* COMPARISON SLIDER */}
|
||||
{!batchMode &&
|
||||
viewType === "slider" &&
|
||||
imagePath.length > 0 &&
|
||||
upscaledImagePath.length > 0 && (
|
||||
<>
|
||||
<ReactCompareSlider
|
||||
itemOne={
|
||||
<>
|
||||
<p className="absolute bottom-1 left-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
|
||||
{t("APP.SLIDER.ORIGINAL_TITLE")}
|
||||
</p>
|
||||
|
||||
<img
|
||||
/* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */
|
||||
src={"file:///" + sanitizedImagePath}
|
||||
alt={t("APP.SLIDER.ORIGINAL_TITLE")}
|
||||
onMouseMove={handleMouseMove}
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
backgroundPosition: "0% 0%",
|
||||
transformOrigin: backgroundPosition,
|
||||
}}
|
||||
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${zoomAmount}%]`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
itemTwo={
|
||||
<>
|
||||
<p className="absolute bottom-1 right-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
|
||||
{t("APP.SLIDER.UPSCAYLED_TITLE")}
|
||||
</p>
|
||||
<img
|
||||
/* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */
|
||||
src={"file:///" + sanitizedUpscaledImagePath}
|
||||
alt={t("APP.SLIDER.UPSCAYLED_TITLE")}
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
backgroundPosition: "0% 0%",
|
||||
transformOrigin: backgroundPosition,
|
||||
}}
|
||||
onMouseMove={handleMouseMove}
|
||||
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${
|
||||
zoomAmount || "100%"
|
||||
}%]`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
className="group h-screen"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainContent;
|
||||
@@ -16,7 +16,7 @@ import { CompressionInput } from "./CompressionInput";
|
||||
import OverwriteToggle from "./OverwriteToggle";
|
||||
import { UpscaylCloudModal } from "../UpscaylCloudModal";
|
||||
import { ResetSettings } from "./ResetSettings";
|
||||
import { featureFlags } from "@common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "@common/feature-flags";
|
||||
import TurnOffNotificationsToggle from "./TurnOffNotificationsToggle";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CustomResolutionInput } from "./CustomResolutionInput";
|
||||
@@ -194,7 +194,7 @@ function SettingsTab({
|
||||
>
|
||||
{t("SETTINGS.SUPPORT.DOCS_BUTTON_TITLE")}
|
||||
</a>
|
||||
{featureFlags.APP_STORE_BUILD && (
|
||||
{FEATURE_FLAGS.APP_STORE_BUILD && (
|
||||
<a
|
||||
className="btn btn-primary"
|
||||
href={`mailto:upscayl@gmail.com?subject=Upscayl%20Issue%3A%20%3CIssue%20name%20here%3E&body=Device%20Name%3A%20%3CYOUR%20DEVICE%20MODEL%3E%0AOperating%20System%3A%20%3CYOUR%20OPERATING%20SYSTEM%20VERSION%3E%0AUpscayl%20Version%3A%20${upscaylVersion}%0A%0AHi%2C%20I'm%20having%20an%20issue%20with%20Upscayl.%20%3CDESCRIBE%20ISSUE%20HERE%3E`}
|
||||
@@ -203,7 +203,7 @@ function SettingsTab({
|
||||
{t("SETTINGS.SUPPORT.EMAIL_BUTTON_TITLE")}
|
||||
</a>
|
||||
)}
|
||||
{!featureFlags.APP_STORE_BUILD && <DonateButton />}
|
||||
{!FEATURE_FLAGS.APP_STORE_BUILD && <DonateButton />}
|
||||
</div>
|
||||
|
||||
<LogArea
|
||||
@@ -253,7 +253,7 @@ function SettingsTab({
|
||||
{/* RESET SETTINGS */}
|
||||
<ResetSettings />
|
||||
|
||||
{featureFlags.SHOW_UPSCAYL_CLOUD_INFO && (
|
||||
{FEATURE_FLAGS.SHOW_UPSCAYL_CLOUD_INFO && (
|
||||
<>
|
||||
<button
|
||||
className="mx-5 mb-5 animate-pulse rounded-btn bg-success p-1 text-sm text-slate-50 shadow-lg shadow-success/40"
|
||||
|
||||
278
renderer/components/sidebar/index.tsx
Normal file
278
renderer/components/sidebar/index.tsx
Normal file
@@ -0,0 +1,278 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { useAtom, useAtomValue } from "jotai";
|
||||
import {
|
||||
batchModeAtom,
|
||||
lensSizeAtom,
|
||||
compressionAtom,
|
||||
dontShowCloudModalAtom,
|
||||
noImageProcessingAtom,
|
||||
savedOutputPathAtom,
|
||||
overwriteAtom,
|
||||
progressAtom,
|
||||
scaleAtom,
|
||||
viewTypeAtom,
|
||||
rememberOutputFolderAtom,
|
||||
customWidthAtom,
|
||||
useCustomWidthAtom,
|
||||
tileSizeAtom,
|
||||
showSidebarAtom,
|
||||
} from "../../atoms/userSettingsAtom";
|
||||
import useLog from "../../components/hooks/useLog";
|
||||
import {
|
||||
BatchUpscaylPayload,
|
||||
DoubleUpscaylPayload,
|
||||
ImageUpscaylPayload,
|
||||
} from "@common/types/types";
|
||||
import { newsAtom, showNewsModalAtom } from "@/atoms/newsAtom";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import Logo from "@/components/icons/Logo";
|
||||
import { translationAtom } from "@/atoms/translations-atom";
|
||||
import LeftPaneImageSteps from "../upscayl-tab/config/LeftPaneImageSteps";
|
||||
import SettingsTab from "../settings-tab";
|
||||
import Footer from "../Footer";
|
||||
import { NewsModal } from "../NewsModal";
|
||||
import Tabs from "../Tabs";
|
||||
import Header from "../Header";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { logAtom } from "@/atoms/logAtom";
|
||||
import { modelsListAtom } from "@/atoms/modelsListAtom";
|
||||
import ELECTRON_COMMANDS from "@common/commands";
|
||||
|
||||
const Sidebar = ({
|
||||
upscaledImagePath,
|
||||
setUpscaledImagePath,
|
||||
batchFolderPath,
|
||||
setUpscaledBatchFolderPath,
|
||||
dimensions,
|
||||
imagePath,
|
||||
selectImageHandler,
|
||||
selectFolderHandler,
|
||||
}: {
|
||||
upscaledImagePath: string;
|
||||
setUpscaledImagePath: React.Dispatch<React.SetStateAction<string>>;
|
||||
batchFolderPath: string;
|
||||
setUpscaledBatchFolderPath: React.Dispatch<React.SetStateAction<string>>;
|
||||
dimensions: {
|
||||
width: number | null;
|
||||
height: number | null;
|
||||
};
|
||||
imagePath: string;
|
||||
selectImageHandler: () => Promise<void>;
|
||||
selectFolderHandler: () => Promise<void>;
|
||||
}) => {
|
||||
const t = useAtomValue(translationAtom);
|
||||
const { logit } = useLog();
|
||||
const { toast } = useToast();
|
||||
|
||||
// LOCAL STATES
|
||||
const [os, setOs] = useState<"linux" | "mac" | "win" | undefined>(undefined);
|
||||
const [model, setModel] = useState("realesrgan-x4plus");
|
||||
const [version, setVersion] = useState("");
|
||||
const [doubleUpscayl, setDoubleUpscayl] = useState(false);
|
||||
const overwrite = useAtomValue(overwriteAtom);
|
||||
const [gpuId, setGpuId] = useState("");
|
||||
const [saveImageAs, setSaveImageAs] = useState("png");
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
const [showCloudModal, setShowCloudModal] = useState(false);
|
||||
|
||||
// ATOMIC STATES
|
||||
const [outputPath, setOutputPath] = useAtom(savedOutputPathAtom);
|
||||
const [compression, setCompression] = useAtom(compressionAtom);
|
||||
const [progress, setProgress] = useAtom(progressAtom);
|
||||
const [batchMode, setBatchMode] = useAtom(batchModeAtom);
|
||||
const [logData, setLogData] = useAtom(logAtom);
|
||||
const [modelOptions, setModelOptions] = useAtom(modelsListAtom);
|
||||
const [scale] = useAtom(scaleAtom);
|
||||
const [dontShowCloudModal, setDontShowCloudModal] = useAtom(
|
||||
dontShowCloudModalAtom,
|
||||
);
|
||||
const noImageProcessing = useAtomValue(noImageProcessingAtom);
|
||||
const [news, setNews] = useAtom(newsAtom);
|
||||
const [showNewsModal, setShowNewsModal] = useAtom(showNewsModalAtom);
|
||||
const viewType = useAtomValue(viewTypeAtom);
|
||||
const lensSize = useAtomValue(lensSizeAtom);
|
||||
const rememberOutputFolder = useAtomValue(rememberOutputFolderAtom);
|
||||
const customWidth = useAtomValue(customWidthAtom);
|
||||
const useCustomWidth = useAtomValue(useCustomWidthAtom);
|
||||
const tileSize = useAtomValue(tileSizeAtom);
|
||||
const [showSidebar, setShowSidebar] = useAtom(showSidebarAtom);
|
||||
|
||||
const handleModelChange = (e: any) => {
|
||||
setModel(e.value);
|
||||
logit("🔀 Model changed: ", e.value);
|
||||
localStorage.setItem(
|
||||
"model",
|
||||
JSON.stringify({ label: e.label, value: e.value }),
|
||||
);
|
||||
};
|
||||
|
||||
const upscaylHandler = async () => {
|
||||
logit("🔄 Resetting Upscaled Image Path");
|
||||
setUpscaledImagePath("");
|
||||
setUpscaledBatchFolderPath("");
|
||||
if (imagePath !== "" || batchFolderPath !== "") {
|
||||
setProgress(t("APP.PROGRESS.WAIT_TITLE"));
|
||||
// Double Upscayl
|
||||
if (doubleUpscayl) {
|
||||
window.electron.send<DoubleUpscaylPayload>(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL,
|
||||
{
|
||||
imagePath,
|
||||
outputPath,
|
||||
model,
|
||||
gpuId: gpuId.length === 0 ? null : gpuId,
|
||||
saveImageAs,
|
||||
scale,
|
||||
noImageProcessing,
|
||||
compression: compression.toString(),
|
||||
customWidth: customWidth > 0 ? customWidth.toString() : null,
|
||||
useCustomWidth,
|
||||
tileSize,
|
||||
},
|
||||
);
|
||||
logit("🏁 DOUBLE_UPSCAYL");
|
||||
} else if (batchMode) {
|
||||
// Batch Upscayl
|
||||
setDoubleUpscayl(false);
|
||||
window.electron.send<BatchUpscaylPayload>(
|
||||
ELECTRON_COMMANDS.FOLDER_UPSCAYL,
|
||||
{
|
||||
batchFolderPath,
|
||||
outputPath,
|
||||
model,
|
||||
gpuId: gpuId.length === 0 ? null : gpuId,
|
||||
saveImageAs,
|
||||
scale,
|
||||
noImageProcessing,
|
||||
compression: compression.toString(),
|
||||
customWidth: customWidth > 0 ? customWidth.toString() : null,
|
||||
useCustomWidth,
|
||||
tileSize,
|
||||
},
|
||||
);
|
||||
logit("🏁 FOLDER_UPSCAYL");
|
||||
} else {
|
||||
// Single Image Upscayl
|
||||
window.electron.send<ImageUpscaylPayload>(ELECTRON_COMMANDS.UPSCAYL, {
|
||||
imagePath,
|
||||
outputPath,
|
||||
model,
|
||||
gpuId: gpuId.length === 0 ? null : gpuId,
|
||||
saveImageAs,
|
||||
scale,
|
||||
overwrite,
|
||||
noImageProcessing,
|
||||
compression: compression.toString(),
|
||||
customWidth: customWidth > 0 ? customWidth.toString() : null,
|
||||
useCustomWidth,
|
||||
tileSize,
|
||||
});
|
||||
logit("🏁 UPSCAYL");
|
||||
}
|
||||
} else {
|
||||
toast({
|
||||
title: t("ERRORS.NO_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.NO_IMAGE_ERROR.DESCRIPTION"),
|
||||
});
|
||||
logit("🚫 No valid image selected");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* TOP LOGO WHEN SIDEBAR IS HIDDEN */}
|
||||
{!showSidebar && (
|
||||
<div className="fixed right-2 top-2 z-50 flex items-center justify-center gap-2 rounded-[7px] bg-base-300 px-2 py-1 font-medium text-base-content ">
|
||||
<Logo className="w-5" />
|
||||
{t("TITLE")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SIDEBAR BUTTON */}
|
||||
<button
|
||||
className={cn(
|
||||
"fixed left-0 top-1/2 z-[999] -translate-y-1/2 rounded-r-full bg-base-100 p-4 ",
|
||||
showSidebar ? "hidden" : "",
|
||||
)}
|
||||
onClick={() => setShowSidebar((prev) => !prev)}
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</button>
|
||||
|
||||
{/* LEFT PANE */}
|
||||
<div
|
||||
className={`relative flex h-screen min-w-[350px] max-w-[350px] flex-col bg-base-100 ${showSidebar ? "" : "hidden"}`}
|
||||
>
|
||||
<button
|
||||
className="absolute -right-0 top-1/2 z-[999] -translate-y-1/2 translate-x-1/2 rounded-full bg-base-100 p-4"
|
||||
onClick={() => setShowSidebar((prev) => !prev)}
|
||||
>
|
||||
<ChevronLeftIcon />
|
||||
</button>
|
||||
|
||||
{/* MACOS TITLEBAR */}
|
||||
{window.electron.platform === "mac" && (
|
||||
<div className="mac-titlebar pt-8"></div>
|
||||
)}
|
||||
{/* HEADER */}
|
||||
<Header version={version} />
|
||||
|
||||
{/* NEWS DIALOG */}
|
||||
<NewsModal
|
||||
show={showNewsModal}
|
||||
setShow={(val: boolean) => {
|
||||
setShowNewsModal(val);
|
||||
setNews((prev) => ({ ...prev, seen: true }));
|
||||
}}
|
||||
news={news}
|
||||
/>
|
||||
|
||||
<Tabs selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
|
||||
|
||||
{selectedTab === 0 && (
|
||||
<LeftPaneImageSteps
|
||||
selectImageHandler={selectImageHandler}
|
||||
selectFolderHandler={selectFolderHandler}
|
||||
handleModelChange={handleModelChange}
|
||||
upscaylHandler={upscaylHandler}
|
||||
batchMode={batchMode}
|
||||
setBatchMode={setBatchMode}
|
||||
imagePath={imagePath}
|
||||
doubleUpscayl={doubleUpscayl}
|
||||
setDoubleUpscayl={setDoubleUpscayl}
|
||||
dimensions={dimensions}
|
||||
setGpuId={setGpuId}
|
||||
model={model}
|
||||
setModel={setModel}
|
||||
setSaveImageAs={setSaveImageAs}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedTab === 1 && (
|
||||
<SettingsTab
|
||||
batchMode={batchMode}
|
||||
setModel={setModel}
|
||||
compression={compression}
|
||||
setCompression={setCompression}
|
||||
gpuId={gpuId}
|
||||
setGpuId={setGpuId}
|
||||
saveImageAs={saveImageAs}
|
||||
setSaveImageAs={setSaveImageAs}
|
||||
logData={logData}
|
||||
os={os}
|
||||
show={showCloudModal}
|
||||
setShow={setShowCloudModal}
|
||||
setDontShowCloudModal={setDontShowCloudModal}
|
||||
/>
|
||||
)}
|
||||
{/* )} */}
|
||||
<Footer />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
customWidthAtom,
|
||||
useCustomWidthAtom,
|
||||
} from "../../../atoms/userSettingsAtom";
|
||||
import { featureFlags } from "@common/feature-flags";
|
||||
import { FEATURE_FLAGS } from "@common/feature-flags";
|
||||
import getModelScale from "@common/check-model-scale";
|
||||
import COMMAND from "@common/commands";
|
||||
import ELECTRON_COMMANDS from "@common/commands";
|
||||
import Select from "react-select";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
@@ -81,7 +81,7 @@ function LeftPaneImageSteps({
|
||||
const t = useAtomValue(translationAtom);
|
||||
|
||||
const outputHandler = async () => {
|
||||
var path = await window.electron.invoke(COMMAND.SELECT_FOLDER);
|
||||
var path = await window.electron.invoke(ELECTRON_COMMANDS.SELECT_FOLDER);
|
||||
if (path !== null) {
|
||||
logit("🗂 Setting Output Path: ", path);
|
||||
setOutputPath(path);
|
||||
@@ -288,7 +288,7 @@ function LeftPaneImageSteps({
|
||||
<span className="leading-none">
|
||||
{t("APP.OUTPUT_PATH_SELECTION.TITLE")}
|
||||
</span>
|
||||
{featureFlags.APP_STORE_BUILD && (
|
||||
{FEATURE_FLAGS.APP_STORE_BUILD && (
|
||||
<button
|
||||
className="badge badge-outline badge-sm cursor-pointer"
|
||||
onClick={() =>
|
||||
@@ -299,7 +299,7 @@ function LeftPaneImageSteps({
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{!outputPath && featureFlags.APP_STORE_BUILD && (
|
||||
{!outputPath && FEATURE_FLAGS.APP_STORE_BUILD && (
|
||||
<div className="text-xs">
|
||||
<span className="rounded-btn bg-base-200 px-2 font-medium uppercase text-base-content/50">
|
||||
{t("APP.OUTPUT_PATH_SELECTION.NOT_SELECTED")}
|
||||
@@ -307,7 +307,7 @@ function LeftPaneImageSteps({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!batchMode && !featureFlags.APP_STORE_BUILD && (
|
||||
{!batchMode && !FEATURE_FLAGS.APP_STORE_BUILD && (
|
||||
<p className="mb-2 text-sm">
|
||||
{!batchMode
|
||||
? t("APP.OUTPUT_PATH_SELECTION.DEFAULT_IMG_PATH")
|
||||
|
||||
1
renderer/lib/valid-formats.ts
Normal file
1
renderer/lib/valid-formats.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const VALID_IMAGE_FORMATS = ["png", "jpg", "jpeg", "jfif", "webp"];
|
||||
@@ -1,15 +1,6 @@
|
||||
"use client";
|
||||
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
|
||||
import COMMAND from "../../common/commands";
|
||||
import { ReactCompareSlider } from "react-compare-slider";
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
import ProgressBar from "../components/upscayl-tab/view/ProgressBar";
|
||||
import RightPaneInfo from "../components/upscayl-tab/view/RightPaneInfo";
|
||||
import ImageOptions from "../components/upscayl-tab/view/ImageOptions";
|
||||
import LeftPaneImageSteps from "../components/upscayl-tab/config/LeftPaneImageSteps";
|
||||
import Tabs from "../components/Tabs";
|
||||
import SettingsTab from "../components/settings-tab";
|
||||
import ELECTRON_COMMANDS from "../../common/commands";
|
||||
import { useAtom, useAtomValue } from "jotai";
|
||||
import { logAtom } from "../atoms/logAtom";
|
||||
import { modelsListAtom } from "../atoms/modelsListAtom";
|
||||
@@ -25,119 +16,102 @@ import {
|
||||
scaleAtom,
|
||||
viewTypeAtom,
|
||||
rememberOutputFolderAtom,
|
||||
showSidebarAtom,
|
||||
customWidthAtom,
|
||||
useCustomWidthAtom,
|
||||
tileSizeAtom,
|
||||
} from "../atoms/userSettingsAtom";
|
||||
import useLog from "../components/hooks/useLog";
|
||||
import { UpscaylCloudModal } from "../components/UpscaylCloudModal";
|
||||
import { featureFlags } from "@common/feature-flags";
|
||||
import {
|
||||
BatchUpscaylPayload,
|
||||
DoubleUpscaylPayload,
|
||||
ImageUpscaylPayload,
|
||||
} from "@common/types/types";
|
||||
import { NewsModal } from "@/components/NewsModal";
|
||||
import { newsAtom, showNewsModalAtom } from "@/atoms/newsAtom";
|
||||
import matter from "gray-matter";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { ToastAction } from "@/components/ui/toast";
|
||||
import Logo from "@/components/icons/Logo";
|
||||
import { sanitizePath } from "@common/sanitize-path";
|
||||
import getDirectoryFromPath from "@common/get-directory-from-path";
|
||||
import { translationAtom } from "@/atoms/translations-atom";
|
||||
import Sidebar from "@/components/sidebar";
|
||||
import MainContent from "@/components/main-content";
|
||||
import getDirectoryFromPath from "@common/get-directory-from-path";
|
||||
import { FEATURE_FLAGS } from "@common/feature-flags";
|
||||
import { VALID_IMAGE_FORMATS } from "@/lib/valid-formats";
|
||||
|
||||
const Home = () => {
|
||||
const allowedFileTypes = ["png", "jpg", "jpeg", "jfif", "webp"];
|
||||
|
||||
const t = useAtomValue(translationAtom);
|
||||
const { logit } = useLog();
|
||||
const { toast } = useToast();
|
||||
|
||||
// LOCAL STATES
|
||||
const [os, setOs] = useState<"linux" | "mac" | "win" | undefined>(undefined);
|
||||
// * SHARED HOOKS AND STATES
|
||||
const [imagePath, setImagePath] = useState("");
|
||||
const [upscaledImagePath, setUpscaledImagePath] = useState("");
|
||||
const [model, setModel] = useState("realesrgan-x4plus");
|
||||
const [version, setVersion] = useState("");
|
||||
const [batchFolderPath, setBatchFolderPath] = useState("");
|
||||
const [doubleUpscayl, setDoubleUpscayl] = useState(false);
|
||||
const overwrite = useAtomValue(overwriteAtom);
|
||||
const [upscaledBatchFolderPath, setUpscaledBatchFolderPath] = useState("");
|
||||
const [doubleUpscaylCounter, setDoubleUpscaylCounter] = useState(0);
|
||||
const [gpuId, setGpuId] = useState("");
|
||||
const [saveImageAs, setSaveImageAs] = useState("png");
|
||||
const [zoomAmount, setZoomAmount] = useState("100");
|
||||
const [backgroundPosition, setBackgroundPosition] = useState("0% 0%");
|
||||
const rememberOutputFolder = useAtomValue(rememberOutputFolderAtom);
|
||||
const [outputPath, setOutputPath] = useAtom(savedOutputPathAtom);
|
||||
const [dimensions, setDimensions] = useState({
|
||||
width: null,
|
||||
height: null,
|
||||
});
|
||||
const [selectedTab, setSelectedTab] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [showCloudModal, setShowCloudModal] = useState(false);
|
||||
const [minSize, setMinSize] = useState(22);
|
||||
const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 });
|
||||
const upscaledImageRef = useRef<HTMLImageElement>(null);
|
||||
const [lensPosition, setLensPosition] = useState({ x: 0, y: 0 });
|
||||
|
||||
// ATOMIC STATES
|
||||
const [outputPath, setOutputPath] = useAtom(savedOutputPathAtom);
|
||||
const [compression, setCompression] = useAtom(compressionAtom);
|
||||
const [progress, setProgress] = useAtom(progressAtom);
|
||||
const [batchMode, setBatchMode] = useAtom(batchModeAtom);
|
||||
const [logData, setLogData] = useAtom(logAtom);
|
||||
const [upscaledImagePath, setUpscaledImagePath] = useState("");
|
||||
const [batchFolderPath, setBatchFolderPath] = useState("");
|
||||
const [upscaledBatchFolderPath, setUpscaledBatchFolderPath] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [doubleUpscaylCounter, setDoubleUpscaylCounter] = useState(0);
|
||||
const [modelOptions, setModelOptions] = useAtom(modelsListAtom);
|
||||
const [scale] = useAtom(scaleAtom);
|
||||
const [dontShowCloudModal, setDontShowCloudModal] = useAtom(
|
||||
dontShowCloudModalAtom,
|
||||
);
|
||||
const noImageProcessing = useAtomValue(noImageProcessingAtom);
|
||||
const [news, setNews] = useAtom(newsAtom);
|
||||
const [showNewsModal, setShowNewsModal] = useAtom(showNewsModalAtom);
|
||||
const viewType = useAtomValue(viewTypeAtom);
|
||||
const lensSize = useAtomValue(lensSizeAtom);
|
||||
const rememberOutputFolder = useAtomValue(rememberOutputFolderAtom);
|
||||
const [showSidebar, setShowSidebar] = useAtom(showSidebarAtom);
|
||||
const customWidth = useAtomValue(customWidthAtom);
|
||||
const useCustomWidth = useAtomValue(useCustomWidthAtom);
|
||||
const tileSize = useAtomValue(tileSizeAtom);
|
||||
const [batchMode, setBatchMode] = useAtom(batchModeAtom);
|
||||
|
||||
const { logit } = useLog();
|
||||
const { toast } = useToast();
|
||||
|
||||
const sanitizedImagePath = useMemo(
|
||||
() => sanitizePath(imagePath),
|
||||
[imagePath],
|
||||
);
|
||||
|
||||
const sanitizedUpscaledImagePath = useMemo(
|
||||
() => sanitizePath(upscaledImagePath),
|
||||
[upscaledImagePath],
|
||||
);
|
||||
|
||||
const handleMouseMoveCompare = (e: React.MouseEvent) => {
|
||||
if (upscaledImageRef.current) {
|
||||
const { left, top, width, height } =
|
||||
upscaledImageRef.current.getBoundingClientRect();
|
||||
const x = e.clientX - left;
|
||||
const y = e.clientY - top;
|
||||
setLensPosition({
|
||||
x: Math.max(0, Math.min(x - lensSize, width - lensSize * 2)),
|
||||
y: Math.max(0, Math.min(y - lensSize / 2, height - lensSize)),
|
||||
});
|
||||
// * SHARED FUNCTIONS
|
||||
const selectImageHandler = async () => {
|
||||
resetImagePaths();
|
||||
var path = await window.electron.invoke(ELECTRON_COMMANDS.SELECT_FILE);
|
||||
if (path === null) return;
|
||||
logit("🖼 Selected Image Path: ", path);
|
||||
setImagePath(path);
|
||||
var dirname = getDirectoryFromPath(path);
|
||||
logit("📁 Selected Image Directory: ", dirname);
|
||||
if (!FEATURE_FLAGS.APP_STORE_BUILD) {
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
}
|
||||
validateImagePath(path);
|
||||
};
|
||||
const validateImagePath = (path: string) => {
|
||||
if (path.length > 0) {
|
||||
logit("🖼 imagePath: ", path);
|
||||
const extension = path.toLocaleLowerCase().split(".").pop();
|
||||
logit("🔤 Extension: ", extension);
|
||||
if (!VALID_IMAGE_FORMATS.includes(extension.toLowerCase())) {
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.DESCRIPTION"),
|
||||
});
|
||||
resetImagePaths();
|
||||
}
|
||||
} else {
|
||||
resetImagePaths();
|
||||
}
|
||||
};
|
||||
const selectFolderHandler = async () => {
|
||||
resetImagePaths();
|
||||
var path = await window.electron.invoke(ELECTRON_COMMANDS.SELECT_FOLDER);
|
||||
if (path !== null) {
|
||||
logit("🖼 Selected Folder Path: ", path);
|
||||
setBatchFolderPath(path);
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(path);
|
||||
}
|
||||
} else {
|
||||
logit("🚫 Folder selection cancelled");
|
||||
setBatchFolderPath("");
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath("");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// SET CONFIG VARIABLES ON FIRST RUN
|
||||
useEffect(() => {
|
||||
// UPSCAYL VERSION
|
||||
const upscaylVersion = navigator?.userAgent?.match(
|
||||
/Upscayl\/([\d\.]+\d+)/,
|
||||
)[1];
|
||||
setVersion(upscaylVersion);
|
||||
}, []);
|
||||
|
||||
// ELECTRON EVENT LISTENERS
|
||||
useEffect(() => {
|
||||
@@ -203,25 +177,19 @@ const Home = () => {
|
||||
resetImagePaths();
|
||||
}
|
||||
};
|
||||
// OS
|
||||
window.electron.on(
|
||||
COMMAND.OS,
|
||||
(_, data: "linux" | "mac" | "win" | undefined) => {
|
||||
if (data) {
|
||||
setOs(data);
|
||||
}
|
||||
},
|
||||
);
|
||||
// LOG
|
||||
window.electron.on(COMMAND.LOG, (_, data: string) => {
|
||||
window.electron.on(ELECTRON_COMMANDS.LOG, (_, data: string) => {
|
||||
logit(`🎒 BACKEND REPORTED: `, data);
|
||||
});
|
||||
// SCALING AND CONVERTING
|
||||
window.electron.on(COMMAND.SCALING_AND_CONVERTING, (_, data: string) => {
|
||||
setProgress(t("APP.PROGRESS.PROCESSING_TITLE"));
|
||||
});
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.SCALING_AND_CONVERTING,
|
||||
(_, data: string) => {
|
||||
setProgress(t("APP.PROGRESS.PROCESSING_TITLE"));
|
||||
},
|
||||
);
|
||||
// UPSCAYL ERROR
|
||||
window.electron.on(COMMAND.UPSCAYL_ERROR, (_, data: string) => {
|
||||
window.electron.on(ELECTRON_COMMANDS.UPSCAYL_ERROR, (_, data: string) => {
|
||||
toast({
|
||||
title: t("ERRORS.GENERIC_ERROR.TITLE"),
|
||||
description: data,
|
||||
@@ -229,77 +197,95 @@ const Home = () => {
|
||||
resetImagePaths();
|
||||
});
|
||||
// UPSCAYL PROGRESS
|
||||
window.electron.on(COMMAND.UPSCAYL_PROGRESS, (_, data: string) => {
|
||||
if (data.length > 0 && data.length < 10) {
|
||||
setProgress(data);
|
||||
} else if (data.includes("converting")) {
|
||||
setProgress(t("APP.PROGRESS.SCALING_CONVERTING_TITLE"));
|
||||
} else if (data.includes("Successful")) {
|
||||
setProgress(t("APP.PROGRESS.SUCCESS_TITLE"));
|
||||
}
|
||||
handleErrors(data);
|
||||
logit(`🚧 UPSCAYL_PROGRESS: `, data);
|
||||
});
|
||||
// FOLDER UPSCAYL PROGRESS
|
||||
window.electron.on(COMMAND.FOLDER_UPSCAYL_PROGRESS, (_, data: string) => {
|
||||
if (data.includes("Successful")) {
|
||||
setProgress(t("APP.PROGRESS.SUCCESS_TITLE"));
|
||||
}
|
||||
if (data.length > 0 && data.length < 10) {
|
||||
setProgress(data);
|
||||
}
|
||||
handleErrors(data);
|
||||
logit(`🚧 FOLDER_UPSCAYL_PROGRESS: `, data);
|
||||
});
|
||||
// DOUBLE UPSCAYL PROGRESS
|
||||
window.electron.on(COMMAND.DOUBLE_UPSCAYL_PROGRESS, (_, data: string) => {
|
||||
if (data.length > 0 && data.length < 10) {
|
||||
if (data === "0.00%") {
|
||||
setDoubleUpscaylCounter(doubleUpscaylCounter + 1);
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.UPSCAYL_PROGRESS,
|
||||
(_, data: string) => {
|
||||
if (data.length > 0 && data.length < 10) {
|
||||
setProgress(data);
|
||||
} else if (data.includes("converting")) {
|
||||
setProgress(t("APP.PROGRESS.SCALING_CONVERTING_TITLE"));
|
||||
} else if (data.includes("Successful")) {
|
||||
setProgress(t("APP.PROGRESS.SUCCESS_TITLE"));
|
||||
}
|
||||
setProgress(data);
|
||||
}
|
||||
handleErrors(data);
|
||||
logit(`🚧 DOUBLE_UPSCAYL_PROGRESS: `, data);
|
||||
});
|
||||
handleErrors(data);
|
||||
logit(`🚧 UPSCAYL_PROGRESS: `, data);
|
||||
},
|
||||
);
|
||||
// FOLDER UPSCAYL PROGRESS
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.FOLDER_UPSCAYL_PROGRESS,
|
||||
(_, data: string) => {
|
||||
if (data.includes("Successful")) {
|
||||
setProgress(t("APP.PROGRESS.SUCCESS_TITLE"));
|
||||
}
|
||||
if (data.length > 0 && data.length < 10) {
|
||||
setProgress(data);
|
||||
}
|
||||
handleErrors(data);
|
||||
logit(`🚧 FOLDER_UPSCAYL_PROGRESS: `, data);
|
||||
},
|
||||
);
|
||||
// DOUBLE UPSCAYL PROGRESS
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_PROGRESS,
|
||||
(_, data: string) => {
|
||||
if (data.length > 0 && data.length < 10) {
|
||||
if (data === "0.00%") {
|
||||
setDoubleUpscaylCounter(doubleUpscaylCounter + 1);
|
||||
}
|
||||
setProgress(data);
|
||||
}
|
||||
handleErrors(data);
|
||||
logit(`🚧 DOUBLE_UPSCAYL_PROGRESS: `, data);
|
||||
},
|
||||
);
|
||||
// UPSCAYL DONE
|
||||
window.electron.on(COMMAND.UPSCAYL_DONE, (_, data: string) => {
|
||||
window.electron.on(ELECTRON_COMMANDS.UPSCAYL_DONE, (_, data: string) => {
|
||||
setProgress("");
|
||||
setUpscaledImagePath(data);
|
||||
logit("upscaledImagePath: ", data);
|
||||
logit(`💯 UPSCAYL_DONE: `, data);
|
||||
});
|
||||
// FOLDER UPSCAYL DONE
|
||||
window.electron.on(COMMAND.FOLDER_UPSCAYL_DONE, (_, data: string) => {
|
||||
setProgress("");
|
||||
setUpscaledBatchFolderPath(data);
|
||||
logit(`💯 FOLDER_UPSCAYL_DONE: `, data);
|
||||
});
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.FOLDER_UPSCAYL_DONE,
|
||||
(_, data: string) => {
|
||||
setProgress("");
|
||||
setUpscaledBatchFolderPath(data);
|
||||
logit(`💯 FOLDER_UPSCAYL_DONE: `, data);
|
||||
},
|
||||
);
|
||||
// DOUBLE UPSCAYL DONE
|
||||
window.electron.on(COMMAND.DOUBLE_UPSCAYL_DONE, (_, data: string) => {
|
||||
setProgress("");
|
||||
setTimeout(() => setUpscaledImagePath(data), 500);
|
||||
setDoubleUpscaylCounter(0);
|
||||
logit(`💯 DOUBLE_UPSCAYL_DONE: `, data);
|
||||
});
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.DOUBLE_UPSCAYL_DONE,
|
||||
(_, data: string) => {
|
||||
setProgress("");
|
||||
setTimeout(() => setUpscaledImagePath(data), 500);
|
||||
setDoubleUpscaylCounter(0);
|
||||
logit(`💯 DOUBLE_UPSCAYL_DONE: `, data);
|
||||
},
|
||||
);
|
||||
// CUSTOM FOLDER LISTENER
|
||||
window.electron.on(COMMAND.CUSTOM_MODEL_FILES_LIST, (_, data: string[]) => {
|
||||
logit(`📜 CUSTOM_MODEL_FILES_LIST: `, data);
|
||||
const newModelOptions = data.map((model) => {
|
||||
return {
|
||||
value: model,
|
||||
label: model,
|
||||
};
|
||||
});
|
||||
// Add newModelsList to modelOptions and remove duplicates
|
||||
const combinedModelOptions = [...modelOptions, ...newModelOptions];
|
||||
const uniqueModelOptions = combinedModelOptions.filter(
|
||||
// Check if any model in the array appears more than once
|
||||
(model, index, array) =>
|
||||
array.findIndex((t) => t.value === model.value) === index,
|
||||
);
|
||||
setModelOptions(uniqueModelOptions);
|
||||
});
|
||||
window.electron.on(
|
||||
ELECTRON_COMMANDS.CUSTOM_MODEL_FILES_LIST,
|
||||
(_, data: string[]) => {
|
||||
logit(`📜 CUSTOM_MODEL_FILES_LIST: `, data);
|
||||
const newModelOptions = data.map((model) => {
|
||||
return {
|
||||
value: model,
|
||||
label: model,
|
||||
};
|
||||
});
|
||||
// Add newModelsList to modelOptions and remove duplicates
|
||||
const combinedModelOptions = [...modelOptions, ...newModelOptions];
|
||||
const uniqueModelOptions = combinedModelOptions.filter(
|
||||
// Check if any model in the array appears more than once
|
||||
(model, index, array) =>
|
||||
array.findIndex((t) => t.value === model.value) === index,
|
||||
);
|
||||
setModelOptions(uniqueModelOptions);
|
||||
},
|
||||
);
|
||||
}, []);
|
||||
|
||||
// FETCH CUSTOM MODELS FROM CUSTOM MODELS PATH
|
||||
@@ -308,7 +294,7 @@ const Home = () => {
|
||||
localStorage.getItem("customModelsPath"),
|
||||
);
|
||||
if (customModelsPath !== null) {
|
||||
window.electron.send(COMMAND.GET_MODELS_LIST, customModelsPath);
|
||||
window.electron.send(ELECTRON_COMMANDS.GET_MODELS_LIST, customModelsPath);
|
||||
logit("🎯 GET_MODELS_LIST: ", customModelsPath);
|
||||
}
|
||||
}, []);
|
||||
@@ -374,230 +360,8 @@ const Home = () => {
|
||||
};
|
||||
|
||||
// UTILS
|
||||
// CHECK IF IMAGE IS VALID
|
||||
const validateImagePath = (path: string) => {
|
||||
if (path.length > 0) {
|
||||
logit("🖼 imagePath: ", path);
|
||||
const extension = path.toLocaleLowerCase().split(".").pop();
|
||||
logit("🔤 Extension: ", extension);
|
||||
if (!allowedFileTypes.includes(extension.toLowerCase())) {
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.DESCRIPTION"),
|
||||
});
|
||||
resetImagePaths();
|
||||
}
|
||||
} else {
|
||||
resetImagePaths();
|
||||
}
|
||||
};
|
||||
|
||||
// HANDLERS
|
||||
const handleMouseMove = useCallback((e: any) => {
|
||||
const { left, top, width, height } = e.target.getBoundingClientRect();
|
||||
const x = ((e.pageX - left) / width) * 100;
|
||||
const y = ((e.pageY - top) / height) * 100;
|
||||
setBackgroundPosition(`${x}% ${y}%`);
|
||||
}, []);
|
||||
|
||||
const selectImageHandler = async () => {
|
||||
resetImagePaths();
|
||||
var path = await window.electron.invoke(COMMAND.SELECT_FILE);
|
||||
if (path === null) return;
|
||||
logit("🖼 Selected Image Path: ", path);
|
||||
setImagePath(path);
|
||||
var dirname = getDirectoryFromPath(path);
|
||||
logit("📁 Selected Image Directory: ", dirname);
|
||||
if (!featureFlags.APP_STORE_BUILD) {
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
}
|
||||
validateImagePath(path);
|
||||
};
|
||||
|
||||
const selectFolderHandler = async () => {
|
||||
resetImagePaths();
|
||||
var path = await window.electron.invoke(COMMAND.SELECT_FOLDER);
|
||||
if (path !== null) {
|
||||
logit("🖼 Selected Folder Path: ", path);
|
||||
setBatchFolderPath(path);
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(path);
|
||||
}
|
||||
} else {
|
||||
logit("🚫 Folder selection cancelled");
|
||||
setBatchFolderPath("");
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath("");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleModelChange = (e: any) => {
|
||||
setModel(e.value);
|
||||
logit("🔀 Model changed: ", e.value);
|
||||
localStorage.setItem(
|
||||
"model",
|
||||
JSON.stringify({ label: e.label, value: e.value }),
|
||||
);
|
||||
};
|
||||
|
||||
// DRAG AND DROP HANDLERS
|
||||
const handleDragEnter = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("drag enter");
|
||||
};
|
||||
const handleDragLeave = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("drag leave");
|
||||
};
|
||||
const handleDragOver = (e) => {
|
||||
e.preventDefault();
|
||||
console.log("drag over");
|
||||
};
|
||||
const openFolderHandler = (e) => {
|
||||
logit("📂 OPEN_FOLDER: ", upscaledBatchFolderPath);
|
||||
window.electron.send(COMMAND.OPEN_FOLDER, upscaledBatchFolderPath);
|
||||
};
|
||||
|
||||
const handleDrop = (e) => {
|
||||
e.preventDefault();
|
||||
resetImagePaths();
|
||||
if (
|
||||
e.dataTransfer.items.length === 0 ||
|
||||
e.dataTransfer.files.length === 0
|
||||
) {
|
||||
logit("👎 No valid files dropped");
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const type = e.dataTransfer.items[0].type;
|
||||
const filePath = e.dataTransfer.files[0].path;
|
||||
const extension = e.dataTransfer.files[0].name.split(".").at(-1);
|
||||
logit("⤵️ Dropped file: ", JSON.stringify({ type, filePath, extension }));
|
||||
if (
|
||||
!type.includes("image") ||
|
||||
!allowedFileTypes.includes(extension.toLowerCase())
|
||||
) {
|
||||
logit("🚫 Invalid file dropped");
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
|
||||
});
|
||||
} else {
|
||||
logit("🖼 Setting image path: ", filePath);
|
||||
setImagePath(filePath);
|
||||
var dirname = getDirectoryFromPath(filePath);
|
||||
logit("🗂 Setting output path: ", dirname);
|
||||
if (!featureFlags.APP_STORE_BUILD) {
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
}
|
||||
validateImagePath(filePath);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePaste = (e) => {
|
||||
resetImagePaths();
|
||||
e.preventDefault();
|
||||
const type = e.clipboardData.items[0].type;
|
||||
const filePath = e.clipboardData.files[0].path;
|
||||
const extension = e.clipboardData.files[0].name.split(".").at(-1);
|
||||
logit("📋 Pasted file: ", JSON.stringify({ type, filePath, extension }));
|
||||
if (
|
||||
!type.includes("image") &&
|
||||
!allowedFileTypes.includes(extension.toLowerCase())
|
||||
) {
|
||||
toast({
|
||||
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
|
||||
});
|
||||
} else {
|
||||
setImagePath(filePath);
|
||||
var dirname = getDirectoryFromPath(filePath);
|
||||
logit("🗂 Setting output path: ", dirname);
|
||||
if (!rememberOutputFolder) {
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const upscaylHandler = async () => {
|
||||
logit("🔄 Resetting Upscaled Image Path");
|
||||
setUpscaledImagePath("");
|
||||
setUpscaledBatchFolderPath("");
|
||||
if (imagePath !== "" || batchFolderPath !== "") {
|
||||
setProgress(t("APP.PROGRESS.WAIT_TITLE"));
|
||||
// Double Upscayl
|
||||
if (doubleUpscayl) {
|
||||
window.electron.send<DoubleUpscaylPayload>(COMMAND.DOUBLE_UPSCAYL, {
|
||||
imagePath,
|
||||
outputPath,
|
||||
model,
|
||||
gpuId: gpuId.length === 0 ? null : gpuId,
|
||||
saveImageAs,
|
||||
scale,
|
||||
noImageProcessing,
|
||||
compression: compression.toString(),
|
||||
customWidth: customWidth > 0 ? customWidth.toString() : null,
|
||||
useCustomWidth,
|
||||
tileSize,
|
||||
});
|
||||
logit("🏁 DOUBLE_UPSCAYL");
|
||||
} else if (batchMode) {
|
||||
// Batch Upscayl
|
||||
setDoubleUpscayl(false);
|
||||
window.electron.send<BatchUpscaylPayload>(COMMAND.FOLDER_UPSCAYL, {
|
||||
batchFolderPath,
|
||||
outputPath,
|
||||
model,
|
||||
gpuId: gpuId.length === 0 ? null : gpuId,
|
||||
saveImageAs,
|
||||
scale,
|
||||
noImageProcessing,
|
||||
compression: compression.toString(),
|
||||
customWidth: customWidth > 0 ? customWidth.toString() : null,
|
||||
useCustomWidth,
|
||||
tileSize,
|
||||
});
|
||||
logit("🏁 FOLDER_UPSCAYL");
|
||||
} else {
|
||||
// Single Image Upscayl
|
||||
window.electron.send<ImageUpscaylPayload>(COMMAND.UPSCAYL, {
|
||||
imagePath,
|
||||
outputPath,
|
||||
model,
|
||||
gpuId: gpuId.length === 0 ? null : gpuId,
|
||||
saveImageAs,
|
||||
scale,
|
||||
overwrite,
|
||||
noImageProcessing,
|
||||
compression: compression.toString(),
|
||||
customWidth: customWidth > 0 ? customWidth.toString() : null,
|
||||
useCustomWidth,
|
||||
tileSize,
|
||||
});
|
||||
logit("🏁 UPSCAYL");
|
||||
}
|
||||
} else {
|
||||
toast({
|
||||
title: t("ERRORS.NO_IMAGE_ERROR.TITLE"),
|
||||
description: t("ERRORS.NO_IMAGE_ERROR.DESCRIPTION"),
|
||||
});
|
||||
logit("🚫 No valid image selected");
|
||||
}
|
||||
};
|
||||
|
||||
const stopHandler = () => {
|
||||
window.electron.send(COMMAND.STOP);
|
||||
logit("🛑 Stopping Upscayl");
|
||||
resetImagePaths();
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -607,321 +371,29 @@ const Home = () => {
|
||||
|
||||
return (
|
||||
<div className="flex h-screen w-screen flex-row overflow-hidden bg-base-300">
|
||||
{/* TOP LOGO WHEN SIDEBAR IS HIDDEN */}
|
||||
{!showSidebar && (
|
||||
<div className="fixed right-2 top-2 z-50 flex items-center justify-center gap-2 rounded-[7px] bg-base-300 px-2 py-1 font-medium text-base-content ">
|
||||
<Logo className="w-5" />
|
||||
{t("TITLE")}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* SIDEBAR BUTTON */}
|
||||
<button
|
||||
className={cn(
|
||||
"fixed left-0 top-1/2 z-[999] -translate-y-1/2 rounded-r-full bg-base-100 p-4 ",
|
||||
showSidebar ? "hidden" : "",
|
||||
)}
|
||||
onClick={() => setShowSidebar((prev) => !prev)}
|
||||
>
|
||||
<ChevronRightIcon />
|
||||
</button>
|
||||
|
||||
{/* LEFT PANE */}
|
||||
<div
|
||||
className={`relative flex h-screen min-w-[350px] max-w-[350px] flex-col bg-base-100 ${showSidebar ? "" : "hidden"}`}
|
||||
>
|
||||
<button
|
||||
className="absolute -right-0 top-1/2 z-[999] -translate-y-1/2 translate-x-1/2 rounded-full bg-base-100 p-4"
|
||||
onClick={() => setShowSidebar((prev) => !prev)}
|
||||
>
|
||||
<ChevronLeftIcon />
|
||||
</button>
|
||||
|
||||
{/* UPSCAYL CLOUD MODAL */}
|
||||
{featureFlags.SHOW_UPSCAYL_CLOUD_INFO && (
|
||||
<UpscaylCloudModal
|
||||
show={showCloudModal}
|
||||
setShow={setShowCloudModal}
|
||||
setDontShowCloudModal={setDontShowCloudModal}
|
||||
/>
|
||||
)}
|
||||
{/* MACOS TITLEBAR */}
|
||||
{window.electron.platform === "mac" && (
|
||||
<div className="mac-titlebar pt-8"></div>
|
||||
)}
|
||||
{/* HEADER */}
|
||||
<Header version={version} />
|
||||
{!dontShowCloudModal && featureFlags.SHOW_UPSCAYL_CLOUD_INFO && (
|
||||
<button
|
||||
className="mx-5 mb-5 animate-pulse rounded-btn bg-success p-1 text-sm text-slate-50 shadow-lg shadow-success/40"
|
||||
onClick={() => {
|
||||
setShowCloudModal(true);
|
||||
}}
|
||||
>
|
||||
{t("INTRO")}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* NEWS DIALOG */}
|
||||
<NewsModal
|
||||
show={showNewsModal}
|
||||
setShow={(val: boolean) => {
|
||||
setShowNewsModal(val);
|
||||
setNews((prev) => ({ ...prev, seen: true }));
|
||||
}}
|
||||
news={news}
|
||||
/>
|
||||
|
||||
<Tabs selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
|
||||
|
||||
{selectedTab === 0 && (
|
||||
<LeftPaneImageSteps
|
||||
selectImageHandler={selectImageHandler}
|
||||
selectFolderHandler={selectFolderHandler}
|
||||
handleModelChange={handleModelChange}
|
||||
upscaylHandler={upscaylHandler}
|
||||
batchMode={batchMode}
|
||||
setBatchMode={setBatchMode}
|
||||
imagePath={imagePath}
|
||||
doubleUpscayl={doubleUpscayl}
|
||||
setDoubleUpscayl={setDoubleUpscayl}
|
||||
dimensions={dimensions}
|
||||
setGpuId={setGpuId}
|
||||
model={model}
|
||||
setModel={setModel}
|
||||
setSaveImageAs={setSaveImageAs}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedTab === 1 && (
|
||||
<SettingsTab
|
||||
batchMode={batchMode}
|
||||
setModel={setModel}
|
||||
compression={compression}
|
||||
setCompression={setCompression}
|
||||
gpuId={gpuId}
|
||||
setGpuId={setGpuId}
|
||||
saveImageAs={saveImageAs}
|
||||
setSaveImageAs={setSaveImageAs}
|
||||
logData={logData}
|
||||
os={os}
|
||||
show={showCloudModal}
|
||||
setShow={setShowCloudModal}
|
||||
setDontShowCloudModal={setDontShowCloudModal}
|
||||
/>
|
||||
)}
|
||||
{/* )} */}
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
{/* RIGHT PANE */}
|
||||
<div
|
||||
className="relative flex h-screen w-full flex-col items-center justify-center"
|
||||
onDrop={(e) => handleDrop(e)}
|
||||
onDragOver={(e) => handleDragOver(e)}
|
||||
onDragEnter={(e) => handleDragEnter(e)}
|
||||
onDragLeave={(e) => handleDragLeave(e)}
|
||||
onDoubleClick={() => {
|
||||
if (batchMode) {
|
||||
selectFolderHandler();
|
||||
} else {
|
||||
selectImageHandler();
|
||||
}
|
||||
}}
|
||||
onPaste={(e) => handlePaste(e)}
|
||||
>
|
||||
{window.electron.platform === "mac" && (
|
||||
<div className="mac-titlebar absolute top-0 h-8 w-full"></div>
|
||||
)}
|
||||
{progress.length > 0 &&
|
||||
upscaledImagePath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0 ? (
|
||||
<ProgressBar
|
||||
batchMode={batchMode}
|
||||
progress={progress}
|
||||
doubleUpscaylCounter={doubleUpscaylCounter}
|
||||
stopHandler={stopHandler}
|
||||
/>
|
||||
) : null}
|
||||
{/* DEFAULT PANE INFO */}
|
||||
{((!batchMode &&
|
||||
imagePath.length === 0 &&
|
||||
upscaledImagePath.length === 0) ||
|
||||
(batchMode &&
|
||||
batchFolderPath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0)) && (
|
||||
<RightPaneInfo version={version} batchMode={batchMode} />
|
||||
)}
|
||||
{/* SHOW SELECTED IMAGE */}
|
||||
{!batchMode &&
|
||||
upscaledImagePath.length === 0 &&
|
||||
imagePath.length > 0 && (
|
||||
<>
|
||||
<ImageOptions
|
||||
zoomAmount={zoomAmount}
|
||||
setZoomAmount={setZoomAmount}
|
||||
resetImagePaths={resetImagePaths}
|
||||
hideZoomOptions={true}
|
||||
/>
|
||||
<img
|
||||
src={"file:///" + sanitizePath(imagePath)}
|
||||
onLoad={(e: any) => {
|
||||
setDimensions({
|
||||
width: e.target.naturalWidth,
|
||||
height: e.target.naturalHeight,
|
||||
});
|
||||
}}
|
||||
draggable="false"
|
||||
alt=""
|
||||
className="h-full w-full bg-gradient-to-br from-base-300 to-base-100 object-contain"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* BATCH UPSCALE SHOW SELECTED FOLDER */}
|
||||
{batchMode &&
|
||||
upscaledBatchFolderPath.length === 0 &&
|
||||
batchFolderPath.length > 0 && (
|
||||
<p className="select-none text-base-content">
|
||||
<span className="font-bold">
|
||||
{t("APP.PROGRESS.BATCH.SELECTED_FOLDER_TITLE")}
|
||||
</span>{" "}
|
||||
{batchFolderPath}
|
||||
</p>
|
||||
)}
|
||||
{/* BATCH UPSCALE DONE INFO */}
|
||||
{batchMode && upscaledBatchFolderPath.length > 0 && (
|
||||
<div className="z-50 flex flex-col items-center">
|
||||
<p className="select-none py-4 font-bold text-base-content">
|
||||
{t("APP.PROGRESS.BATCH.DONE_TITLE")}
|
||||
</p>
|
||||
<button
|
||||
className="bg-gradient-blue btn btn-primary rounded-btn p-3 font-medium text-white/90 transition-colors"
|
||||
onClick={openFolderHandler}
|
||||
>
|
||||
{t("APP.PROGRESS.BATCH.OPEN_UPSCAYLED_FOLDER_TITLE")}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<ImageOptions
|
||||
zoomAmount={zoomAmount}
|
||||
setZoomAmount={setZoomAmount}
|
||||
resetImagePaths={resetImagePaths}
|
||||
/>
|
||||
{!batchMode &&
|
||||
viewType === "lens" &&
|
||||
upscaledImagePath &&
|
||||
imagePath && (
|
||||
<div
|
||||
className="group relative h-full w-full overflow-hidden"
|
||||
onMouseMove={handleMouseMoveCompare}
|
||||
>
|
||||
{/* UPSCALED IMAGE */}
|
||||
<img
|
||||
className="h-full w-full object-contain"
|
||||
src={"file:///" + sanitizedUpscaledImagePath}
|
||||
alt="Upscaled"
|
||||
ref={upscaledImageRef}
|
||||
/>
|
||||
{/* LENS */}
|
||||
<div
|
||||
className="pointer-events-none absolute opacity-0 transition-opacity before:absolute before:left-1/2 before:h-full before:w-[2px] before:bg-white group-hover:opacity-100"
|
||||
style={{
|
||||
left: `${lensPosition.x}px`,
|
||||
top: `${lensPosition.y}px`,
|
||||
width: lensSize * 2,
|
||||
height: lensSize,
|
||||
border: "2px solid white",
|
||||
boxShadow: "0 0 0 9999px rgba(0, 0, 0, 0.5)",
|
||||
}}
|
||||
>
|
||||
<div className="flex h-full w-full">
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<img
|
||||
src={"file:///" + sanitizedImagePath}
|
||||
alt="Original"
|
||||
className="h-full w-full"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
objectPosition: `${-lensPosition.x}px ${-lensPosition.y}px`,
|
||||
transform: `scale(${parseInt(zoomAmount) / 100})`,
|
||||
transformOrigin: "top left",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<img
|
||||
src={"file:///" + sanitizedUpscaledImagePath}
|
||||
alt="Upscaled"
|
||||
className="h-full w-full"
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
objectPosition: `${-lensPosition.x}px ${-lensPosition.y}px`,
|
||||
transform: `scale(${parseInt(zoomAmount) / 100})`,
|
||||
transformOrigin: "top left",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 flex w-full items-center justify-around bg-black bg-opacity-50 p-1 px-2 text-center text-xs text-white backdrop-blur-sm">
|
||||
<span>Original</span>
|
||||
<span>Upscayl</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{/* COMPARISON SLIDER */}
|
||||
{!batchMode &&
|
||||
viewType === "slider" &&
|
||||
imagePath.length > 0 &&
|
||||
upscaledImagePath.length > 0 && (
|
||||
<>
|
||||
<ReactCompareSlider
|
||||
itemOne={
|
||||
<>
|
||||
<p className="absolute bottom-1 left-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
|
||||
{t("APP.SLIDER.ORIGINAL_TITLE")}
|
||||
</p>
|
||||
|
||||
<img
|
||||
/* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */
|
||||
src={"file:///" + sanitizedImagePath}
|
||||
alt={t("APP.SLIDER.ORIGINAL_TITLE")}
|
||||
onMouseMove={handleMouseMove}
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
backgroundPosition: "0% 0%",
|
||||
transformOrigin: backgroundPosition,
|
||||
}}
|
||||
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${zoomAmount}%]`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
itemTwo={
|
||||
<>
|
||||
<p className="absolute bottom-1 right-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
|
||||
{t("APP.SLIDER.UPSCAYLED_TITLE")}
|
||||
</p>
|
||||
<img
|
||||
/* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */
|
||||
src={"file:///" + sanitizedUpscaledImagePath}
|
||||
alt={t("APP.SLIDER.UPSCAYLED_TITLE")}
|
||||
style={{
|
||||
objectFit: "contain",
|
||||
backgroundPosition: "0% 0%",
|
||||
transformOrigin: backgroundPosition,
|
||||
}}
|
||||
onMouseMove={handleMouseMove}
|
||||
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${
|
||||
zoomAmount || "100%"
|
||||
}%]`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
className="group h-screen"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Sidebar
|
||||
imagePath={imagePath}
|
||||
dimensions={dimensions}
|
||||
upscaledImagePath={upscaledImagePath}
|
||||
setUpscaledImagePath={setUpscaledImagePath}
|
||||
batchFolderPath={batchFolderPath}
|
||||
setUpscaledBatchFolderPath={setUpscaledBatchFolderPath}
|
||||
selectImageHandler={selectImageHandler}
|
||||
selectFolderHandler={selectFolderHandler}
|
||||
/>
|
||||
<MainContent
|
||||
imagePath={imagePath}
|
||||
resetImagePaths={resetImagePaths}
|
||||
upscaledBatchFolderPath={upscaledBatchFolderPath}
|
||||
setImagePath={setImagePath}
|
||||
validateImagePath={validateImagePath}
|
||||
selectFolderHandler={selectFolderHandler}
|
||||
selectImageHandler={selectImageHandler}
|
||||
batchFolderPath={batchFolderPath}
|
||||
upscaledImagePath={upscaledImagePath}
|
||||
doubleUpscaylCounter={doubleUpscaylCounter}
|
||||
setDimensions={setDimensions}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
1
renderer/renderer.d.ts
vendored
1
renderer/renderer.d.ts
vendored
@@ -2,6 +2,7 @@ import { IpcRenderer } from "electron";
|
||||
|
||||
export interface IElectronAPI {
|
||||
on: (command, func?) => IpcRenderer;
|
||||
off: (command, func?) => IpcRenderer;
|
||||
send: <T>(command, func?: T) => IpcRenderer;
|
||||
invoke: (command, func?) => any;
|
||||
platform: "mac" | "win" | "linux";
|
||||
|
||||
Reference in New Issue
Block a user