1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-12-01 02:27:16 +01:00
upscayl/renderer/pages/index.tsx

911 lines
31 KiB
TypeScript
Raw Normal View History

2023-09-03 11:16:48 +02:00
"use client";
import { useState, useEffect, useCallback, useMemo } from "react";
2024-01-16 08:33:43 +01:00
import COMMAND from "../../common/commands";
import { ReactCompareSlider } from "react-compare-slider";
2022-11-11 21:39:28 +01:00
import Header from "../components/Header";
import Footer from "../components/Footer";
2023-07-22 13:07:53 +02:00
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";
2023-03-18 18:08:50 +01:00
import Tabs from "../components/Tabs";
2023-07-22 13:07:53 +02:00
import SettingsTab from "../components/settings-tab";
2023-11-22 16:54:02 +01:00
import { useAtom, useAtomValue } from "jotai";
2023-04-08 08:53:32 +02:00
import { logAtom } from "../atoms/logAtom";
2023-04-09 07:48:53 +02:00
import { modelsListAtom } from "../atoms/modelsListAtom";
2023-09-03 11:16:48 +02:00
import {
batchModeAtom,
2024-01-23 09:44:32 +01:00
lensSizeAtom,
2023-11-22 16:57:44 +01:00
compressionAtom,
2023-09-03 11:16:48 +02:00
dontShowCloudModalAtom,
2023-11-22 16:54:02 +01:00
noImageProcessingAtom,
2024-04-09 20:11:24 +02:00
savedOutputPathAtom,
overwriteAtom,
2023-11-10 12:41:35 +01:00
progressAtom,
2023-09-03 11:16:48 +02:00
scaleAtom,
2024-01-23 09:44:32 +01:00
viewTypeAtom,
2024-02-14 07:32:52 +01:00
rememberOutputFolderAtom,
2024-04-17 18:18:45 +02:00
showSidebarAtom,
2024-04-20 17:44:42 +02:00
customWidthAtom,
useCustomWidthAtom,
tileSizeAtom,
2023-09-03 11:16:48 +02:00
} from "../atoms/userSettingsAtom";
2023-04-30 03:44:47 +02:00
import useLog from "../components/hooks/useLog";
import { UpscaylCloudModal } from "../components/UpscaylCloudModal";
2023-10-25 13:44:22 +02:00
import { featureFlags } from "@common/feature-flags";
2023-11-22 16:54:02 +01:00
import {
BatchUpscaylPayload,
DoubleUpscaylPayload,
ImageUpscaylPayload,
} from "@common/types/types";
2023-11-23 10:25:55 +01:00
import { NewsModal } from "@/components/NewsModal";
2023-11-26 09:04:03 +01:00
import { newsAtom, showNewsModalAtom } from "@/atoms/newsAtom";
import matter from "gray-matter";
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
2024-04-17 18:18:45 +02:00
import { cn } from "@/lib/utils";
2024-04-21 16:04:59 +02:00
import { useToast } from "@/components/ui/use-toast";
import { ToastAction } from "@/components/ui/toast";
2024-04-24 13:08:27 +02:00
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";
2023-03-31 12:33:48 +02:00
2022-11-11 21:39:28 +01:00
const Home = () => {
const allowedFileTypes = ["png", "jpg", "jpeg", "jfif", "webp"];
2023-11-23 09:53:09 +01:00
const t = useAtomValue(translationAtom);
2023-11-22 16:54:02 +01:00
// LOCAL STATES
2023-08-14 12:56:11 +02:00
const [os, setOs] = useState<"linux" | "mac" | "win" | undefined>(undefined);
2023-11-23 09:53:09 +01:00
const [imagePath, setImagePath] = useState("");
const [upscaledImagePath, setUpscaledImagePath] = useState("");
2022-12-24 08:17:54 +01:00
const [model, setModel] = useState("realesrgan-x4plus");
2022-11-11 21:39:28 +01:00
const [version, setVersion] = useState("");
const [batchFolderPath, setBatchFolderPath] = useState("");
const [doubleUpscayl, setDoubleUpscayl] = useState(false);
const overwrite = useAtomValue(overwriteAtom);
2023-11-22 16:54:02 +01:00
const [upscaledBatchFolderPath, setUpscaledBatchFolderPath] = useState("");
2022-12-02 15:21:42 +01:00
const [doubleUpscaylCounter, setDoubleUpscaylCounter] = useState(0);
2022-12-16 17:20:46 +01:00
const [gpuId, setGpuId] = useState("");
const [saveImageAs, setSaveImageAs] = useState("png");
2024-01-23 09:44:32 +01:00
const [zoomAmount, setZoomAmount] = useState("100");
2022-12-21 11:32:45 +01:00
const [backgroundPosition, setBackgroundPosition] = useState("0% 0%");
2022-12-24 08:17:54 +01:00
const [dimensions, setDimensions] = useState({
width: null,
height: null,
});
2023-03-18 18:08:50 +01:00
const [selectedTab, setSelectedTab] = useState(0);
2023-11-22 16:54:02 +01:00
const [isLoading, setIsLoading] = useState(true);
const [showCloudModal, setShowCloudModal] = useState(false);
2024-04-17 18:18:45 +02:00
const [minSize, setMinSize] = useState(22);
2024-01-23 09:44:32 +01:00
const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 });
2023-11-22 16:54:02 +01:00
// ATOMIC STATES
2024-04-09 20:11:24 +02:00
const [outputPath, setOutputPath] = useAtom(savedOutputPathAtom);
2023-11-22 16:57:44 +01:00
const [compression, setCompression] = useAtom(compressionAtom);
2023-11-22 16:54:02 +01:00
const [progress, setProgress] = useAtom(progressAtom);
const [batchMode, setBatchMode] = useAtom(batchModeAtom);
2023-04-08 08:53:32 +02:00
const [logData, setLogData] = useAtom(logAtom);
2023-04-09 07:48:53 +02:00
const [modelOptions, setModelOptions] = useAtom(modelsListAtom);
2023-04-14 12:31:37 +02:00
const [scale] = useAtom(scaleAtom);
2023-09-03 11:16:48 +02:00
const [dontShowCloudModal, setDontShowCloudModal] = useAtom(
2024-02-07 02:23:19 +01:00
dontShowCloudModalAtom,
2023-09-03 11:16:48 +02:00
);
2023-11-22 16:54:02 +01:00
const noImageProcessing = useAtomValue(noImageProcessingAtom);
2023-11-23 06:58:29 +01:00
const [news, setNews] = useAtom(newsAtom);
2023-11-26 09:04:03 +01:00
const [showNewsModal, setShowNewsModal] = useAtom(showNewsModalAtom);
2024-01-23 09:44:32 +01:00
const viewType = useAtomValue(viewTypeAtom);
const lensSize = useAtomValue(lensSizeAtom);
2024-02-14 07:32:52 +01:00
const rememberOutputFolder = useAtomValue(rememberOutputFolderAtom);
2024-04-17 18:18:45 +02:00
const [showSidebar, setShowSidebar] = useAtom(showSidebarAtom);
2024-04-20 17:44:42 +02:00
const customWidth = useAtomValue(customWidthAtom);
const useCustomWidth = useAtomValue(useCustomWidthAtom);
const tileSize = useAtomValue(tileSizeAtom);
2023-04-30 03:44:47 +02:00
const { logit } = useLog();
2024-04-21 16:04:59 +02:00
const { toast } = useToast();
2023-04-30 03:44:47 +02:00
const sanitizedImagePath = useMemo(
() => sanitizePath(imagePath),
[imagePath],
);
const sanitizedUpscaledImagePath = useMemo(
() => sanitizePath(upscaledImagePath),
[upscaledImagePath],
);
2024-01-23 09:44:32 +01:00
const handleMouseMoveCompare = (e: React.MouseEvent) => {
const { left, top, height, width } =
e.currentTarget.getBoundingClientRect();
const x = e.clientX - left;
const y = e.clientY - top;
setCursorPosition({ x, y });
const xZoom = ((e.pageX - left) / width) * 100;
const yZoom = ((e.pageY - top) / height) * 100;
setBackgroundPosition(`${xZoom}% ${yZoom}%`);
};
2023-11-23 09:53:09 +01:00
// SET CONFIG VARIABLES ON FIRST RUN
2022-11-11 21:39:28 +01:00
useEffect(() => {
2023-11-23 09:53:09 +01:00
// UPSCAYL VERSION
const upscaylVersion = navigator?.userAgent?.match(
2024-02-07 02:23:19 +01:00
/Upscayl\/([\d\.]+\d+)/,
2023-11-23 09:53:09 +01:00
)[1];
setVersion(upscaylVersion);
}, []);
2023-11-23 10:25:55 +01:00
// ELECTRON EVENT LISTENERS
2023-11-23 09:53:09 +01:00
useEffect(() => {
2023-04-08 08:53:32 +02:00
const handleErrors = (data: string) => {
2024-04-21 16:04:59 +02:00
if (data.includes("Invalid GPU")) {
toast({
title: t("ERRORS.GPU_ERROR.TITLE"),
description: t("ERRORS.GPU_ERROR.DESCRIPTION", { data }),
2024-04-21 16:04:59 +02:00
action: (
2024-04-22 09:55:44 +02:00
<div className="flex flex-col gap-2">
<ToastAction
altText={t("ERRORS.COPY_ERROR.TITLE")}
2024-04-22 09:55:44 +02:00
onClick={() => {
navigator.clipboard.writeText(data);
}}
>
{t("ERRORS.COPY_ERROR.TITLE")}
2024-04-22 09:55:44 +02:00
</ToastAction>
2024-04-24 22:28:03 +02:00
<a href="https://docs.upscayl.org/" target="_blank">
<ToastAction altText={t("ERRORS.OPEN_DOCS_TITLE")}>
{t("ERRORS.OPEN_DOCS_BUTTON_TITLE")}
</ToastAction>
2024-04-22 09:55:44 +02:00
</a>
</div>
2024-04-21 16:04:59 +02:00
),
});
2022-11-11 21:39:28 +01:00
resetImagePaths();
2024-04-21 16:04:59 +02:00
} else if (data.includes("write") || data.includes("read")) {
2022-11-11 21:39:28 +01:00
if (batchMode) return;
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.READ_WRITE_ERROR.TITLE"),
description: t("ERRORS.READ_WRITE_ERROR.DESCRIPTION", { data }),
2024-04-21 16:04:59 +02:00
action: (
2024-04-22 09:55:44 +02:00
<div className="flex flex-col gap-2">
<ToastAction
altText="Copy Error"
onClick={() => {
navigator.clipboard.writeText(data);
}}
>
{t("ERRORS.COPY_ERROR.TITLE")}
2024-04-22 09:55:44 +02:00
</ToastAction>
2024-04-24 22:28:03 +02:00
<a href="https://docs.upscayl.org/" target="_blank">
<ToastAction altText={t("ERRORS.OPEN_DOCS_TITLE")}>
{t("ERRORS.OPEN_DOCS_BUTTON_TITLE")}
</ToastAction>
2024-04-22 09:55:44 +02:00
</a>
</div>
2024-04-21 16:04:59 +02:00
),
});
resetImagePaths();
} else if (data.includes("tile size")) {
toast({
title: t("ERRORS.TILE_SIZE_ERROR.TITLE"),
description: t("ERRORS.TILE_SIZE_ERROR.DESCRIPTION", { data }),
2024-04-21 16:04:59 +02:00
});
2022-11-11 21:39:28 +01:00
resetImagePaths();
} else if (data.includes("uncaughtException")) {
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.EXCEPTION_ERROR.TITLE"),
description: t("ERRORS.EXCEPTION_ERROR.DESCRIPTION"),
2024-04-21 16:04:59 +02:00
});
2022-11-11 21:39:28 +01:00
resetImagePaths();
}
};
2023-11-23 09:53:09 +01:00
// OS
2023-08-14 12:55:30 +02:00
window.electron.on(
2023-09-10 19:42:18 +02:00
COMMAND.OS,
2023-08-14 12:55:30 +02:00
(_, data: "linux" | "mac" | "win" | undefined) => {
if (data) {
setOs(data);
}
2024-02-07 02:23:19 +01:00
},
2023-08-14 12:55:30 +02:00
);
2023-04-14 12:31:37 +02:00
// LOG
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.LOG, (_, data: string) => {
2024-04-25 12:43:16 +02:00
logit(`🎒 BACKEND REPORTED: `, data);
2023-04-14 12:31:37 +02:00
});
2023-11-23 09:53:09 +01:00
// SCALING AND CONVERTING
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.SCALING_AND_CONVERTING, (_, data: string) => {
setProgress(t("APP.PROGRESS.PROCESSING_TITLE"));
2023-09-09 14:18:00 +02:00
});
2023-11-23 09:53:09 +01:00
// UPSCAYL ERROR
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.UPSCAYL_ERROR, (_, data: string) => {
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.GENERIC_ERROR.TITLE"),
2024-04-21 16:04:59 +02:00
description: data,
});
2023-09-09 13:03:16 +02:00
resetImagePaths();
});
2022-12-16 17:20:46 +01:00
// UPSCAYL PROGRESS
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.UPSCAYL_PROGRESS, (_, data: string) => {
2022-11-11 21:39:28 +01:00
if (data.length > 0 && data.length < 10) {
setProgress(data);
2023-09-04 17:59:17 +02:00
} else if (data.includes("converting")) {
setProgress(t("APP.PROGRESS.SCALING_CONVERTING_TITLE"));
2023-10-21 16:14:42 +02:00
} else if (data.includes("Successful")) {
setProgress(t("APP.PROGRESS.SUCCESS_TITLE"));
2022-11-11 21:39:28 +01:00
}
handleErrors(data);
logit(`🚧 UPSCAYL_PROGRESS: `, data);
2022-11-11 21:39:28 +01:00
});
2022-12-16 17:20:46 +01:00
// FOLDER UPSCAYL PROGRESS
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.FOLDER_UPSCAYL_PROGRESS, (_, data: string) => {
2023-10-21 17:50:59 +02:00
if (data.includes("Successful")) {
setProgress(t("APP.PROGRESS.SUCCESS_TITLE"));
2023-10-21 17:50:59 +02:00
}
2022-11-11 21:39:28 +01:00
if (data.length > 0 && data.length < 10) {
setProgress(data);
}
handleErrors(data);
logit(`🚧 FOLDER_UPSCAYL_PROGRESS: `, data);
2022-11-11 21:39:28 +01:00
});
2022-12-16 17:20:46 +01:00
// DOUBLE UPSCAYL PROGRESS
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.DOUBLE_UPSCAYL_PROGRESS, (_, data: string) => {
2022-11-11 21:39:28 +01:00
if (data.length > 0 && data.length < 10) {
2022-12-02 15:21:42 +01:00
if (data === "0.00%") {
setDoubleUpscaylCounter(doubleUpscaylCounter + 1);
}
2022-11-11 21:39:28 +01:00
setProgress(data);
}
handleErrors(data);
logit(`🚧 DOUBLE_UPSCAYL_PROGRESS: `, data);
2022-11-11 21:39:28 +01:00
});
2022-12-16 17:20:46 +01:00
// UPSCAYL DONE
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.UPSCAYL_DONE, (_, data: string) => {
2022-11-11 21:39:28 +01:00
setProgress("");
2023-09-13 18:15:42 +02:00
setUpscaledImagePath(data);
2023-07-22 15:00:46 +02:00
logit("upscaledImagePath: ", data);
logit(`💯 UPSCAYL_DONE: `, data);
2022-11-11 21:39:28 +01:00
});
2022-12-16 17:20:46 +01:00
// FOLDER UPSCAYL DONE
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.FOLDER_UPSCAYL_DONE, (_, data: string) => {
2022-11-11 21:39:28 +01:00
setProgress("");
setUpscaledBatchFolderPath(data);
logit(`💯 FOLDER_UPSCAYL_DONE: `, data);
2022-11-11 21:39:28 +01:00
});
2022-12-16 17:20:46 +01:00
// DOUBLE UPSCAYL DONE
2023-09-10 19:42:18 +02:00
window.electron.on(COMMAND.DOUBLE_UPSCAYL_DONE, (_, data: string) => {
2022-12-02 15:21:42 +01:00
setProgress("");
2023-09-11 05:57:16 +02:00
setTimeout(() => setUpscaledImagePath(data), 500);
2022-12-02 15:21:42 +01:00
setDoubleUpscaylCounter(0);
logit(`💯 DOUBLE_UPSCAYL_DONE: `, data);
2022-11-11 21:39:28 +01:00
});
2023-04-09 07:48:53 +02:00
// CUSTOM FOLDER LISTENER
2023-09-10 19:42:18 +02:00
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) =>
2024-02-07 02:23:19 +01:00
array.findIndex((t) => t.value === model.value) === index,
2023-09-10 19:42:18 +02:00
);
setModelOptions(uniqueModelOptions);
});
2023-04-09 07:48:53 +02:00
}, []);
2023-11-23 09:53:09 +01:00
// FETCH CUSTOM MODELS FROM CUSTOM MODELS PATH
2023-04-09 07:48:53 +02:00
useEffect(() => {
const customModelsPath = JSON.parse(
2024-02-07 02:23:19 +01:00
localStorage.getItem("customModelsPath"),
2023-04-09 07:48:53 +02:00
);
if (customModelsPath !== null) {
2023-09-10 19:42:18 +02:00
window.electron.send(COMMAND.GET_MODELS_LIST, customModelsPath);
logit("🎯 GET_MODELS_LIST: ", customModelsPath);
2023-04-09 07:48:53 +02:00
}
2022-11-11 21:39:28 +01:00
}, []);
2023-11-23 09:53:09 +01:00
// FETCH NEWS
2023-11-23 06:58:29 +01:00
useEffect(() => {
// TODO: ADD AN ABOUT TAB
if (window && window.navigator.onLine === false) return;
2023-12-03 07:36:00 +01:00
try {
fetch("https://raw.githubusercontent.com/upscayl/upscayl/main/news.md", {
cache: "no-cache",
2023-11-23 09:53:09 +01:00
})
2023-12-03 07:36:00 +01:00
.then((res) => {
return res.text();
})
.then((result) => {
const newsData = result;
if (!newsData) {
console.log("📰 Could not fetch news data");
return;
2023-11-26 09:04:03 +01:00
}
2023-12-03 07:36:00 +01:00
const markdownData = matter(newsData);
if (!markdownData) return;
if (markdownData && markdownData.data.dontShow) {
2023-12-03 07:36:00 +01:00
return;
}
if (
markdownData &&
news &&
markdownData?.data?.version === news?.data?.version
) {
console.log("📰 News is up to date");
if (showNewsModal === false) {
setShowNewsModal(false);
}
} else if (markdownData) {
setNews(matter(newsData));
setShowNewsModal(true);
}
});
} catch (error) {
console.log("Could not fetch Upscayl News");
}
2023-11-26 09:04:03 +01:00
}, [news]);
2023-11-23 06:58:29 +01:00
2023-11-23 09:53:09 +01:00
// LOADING STATE
2023-10-15 05:57:11 +02:00
useEffect(() => {
setIsLoading(false);
}, []);
// HANDLERS
2022-12-16 17:20:46 +01:00
const resetImagePaths = () => {
logit("🔄 Resetting image paths");
2022-12-24 08:17:54 +01:00
setDimensions({
width: null,
height: null,
});
2022-12-16 17:20:46 +01:00
setProgress("");
2023-11-23 09:53:09 +01:00
setImagePath("");
2022-12-16 17:20:46 +01:00
setUpscaledImagePath("");
setBatchFolderPath("");
setUpscaledBatchFolderPath("");
};
2023-11-23 09:53:09 +01:00
// 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())) {
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
description: t("ERRORS.INVALID_IMAGE_ERROR.DESCRIPTION"),
2024-04-21 16:04:59 +02:00
});
2023-11-23 09:53:09 +01:00
resetImagePaths();
}
} else {
resetImagePaths();
}
};
2022-12-16 17:20:46 +01:00
// HANDLERS
2023-04-08 08:53:32 +02:00
const handleMouseMove = useCallback((e: any) => {
2022-12-21 11:32:45 +01:00
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}%`);
2023-04-08 08:53:32 +02:00
}, []);
2022-12-21 11:32:45 +01:00
2022-11-11 21:39:28 +01:00
const selectImageHandler = async () => {
resetImagePaths();
2023-09-10 19:42:18 +02:00
var path = await window.electron.invoke(COMMAND.SELECT_FILE);
2023-11-23 09:53:09 +01:00
if (path === null) return;
logit("🖼 Selected Image Path: ", path);
setImagePath(path);
var dirname = getDirectoryFromPath(path);
2023-11-23 09:53:09 +01:00
logit("📁 Selected Image Directory: ", dirname);
if (!featureFlags.APP_STORE_BUILD) {
2024-02-14 07:32:52 +01:00
if (!rememberOutputFolder) {
setOutputPath(dirname);
}
2022-11-11 21:39:28 +01:00
}
2023-11-23 09:53:09 +01:00
validateImagePath(path);
2022-11-11 21:39:28 +01:00
};
const selectFolderHandler = async () => {
resetImagePaths();
2023-09-10 19:42:18 +02:00
var path = await window.electron.invoke(COMMAND.SELECT_FOLDER);
2023-04-09 07:16:15 +02:00
if (path !== null) {
logit("🖼 Selected Folder Path: ", path);
2022-11-11 21:39:28 +01:00
setBatchFolderPath(path);
2024-02-14 07:32:52 +01:00
if (!rememberOutputFolder) {
setOutputPath(path);
}
2023-05-01 08:34:45 +02:00
} else {
logit("🚫 Folder selection cancelled");
2023-05-01 08:34:45 +02:00
setBatchFolderPath("");
2024-02-14 07:32:52 +01:00
if (!rememberOutputFolder) {
setOutputPath("");
}
2022-11-11 21:39:28 +01:00
}
};
2023-04-08 08:53:32 +02:00
const handleModelChange = (e: any) => {
2022-11-11 21:39:28 +01:00
setModel(e.value);
logit("🔀 Model changed: ", e.value);
2022-12-24 09:45:15 +01:00
localStorage.setItem(
"model",
2024-02-07 02:23:19 +01:00
JSON.stringify({ label: e.label, value: e.value }),
2022-12-24 09:45:15 +01:00
);
2022-11-11 21:39:28 +01:00
};
2022-12-16 17:20:46 +01:00
// DRAG AND DROP HANDLERS
2022-11-11 21:39:28 +01:00
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);
2023-09-10 19:42:18 +02:00
window.electron.send(COMMAND.OPEN_FOLDER, upscaledBatchFolderPath);
2022-11-11 21:39:28 +01:00
};
const handleDrop = (e) => {
e.preventDefault();
resetImagePaths();
2023-04-20 20:34:49 +02:00
if (
e.dataTransfer.items.length === 0 ||
e.dataTransfer.files.length === 0
) {
logit("👎 No valid files dropped");
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
2024-04-21 16:04:59 +02:00
});
2023-04-20 20:34:49 +02:00
return;
}
2022-11-11 21:39:28 +01:00
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 }));
2022-11-11 21:39:28 +01:00
if (
2023-08-14 12:55:30 +02:00
!type.includes("image") ||
!allowedFileTypes.includes(extension.toLowerCase())
2022-11-11 21:39:28 +01:00
) {
logit("🚫 Invalid file dropped");
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
2024-04-21 16:04:59 +02:00
});
2022-11-11 21:39:28 +01:00
} else {
2023-08-14 12:55:30 +02:00
logit("🖼 Setting image path: ", filePath);
2023-11-23 09:53:09 +01:00
setImagePath(filePath);
var dirname = getDirectoryFromPath(filePath);
logit("🗂 Setting output path: ", dirname);
2024-02-14 07:32:52 +01:00
if (!featureFlags.APP_STORE_BUILD) {
if (!rememberOutputFolder) {
setOutputPath(dirname);
}
}
2023-11-23 09:53:09 +01:00
validateImagePath(filePath);
2022-11-11 21:39:28 +01:00
}
};
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 }));
2022-11-11 21:39:28 +01:00
if (
!type.includes("image") &&
!allowedFileTypes.includes(extension.toLowerCase())
) {
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.INVALID_IMAGE_ERROR.TITLE"),
description: t("ERRORS.INVALID_IMAGE_ERROR.ADDITIONAL_DESCRIPTION"),
2024-04-21 16:04:59 +02:00
});
2022-11-11 21:39:28 +01:00
} else {
2023-11-23 09:53:09 +01:00
setImagePath(filePath);
var dirname = getDirectoryFromPath(filePath);
logit("🗂 Setting output path: ", dirname);
2024-02-14 07:32:52 +01:00
if (!rememberOutputFolder) {
setOutputPath(dirname);
2023-04-28 14:47:51 +02:00
}
2022-11-11 21:39:28 +01:00
}
};
const upscaylHandler = async () => {
2023-08-14 12:55:30 +02:00
logit("🔄 Resetting Upscaled Image Path");
setUpscaledImagePath("");
2023-09-09 15:01:31 +02:00
setUpscaledBatchFolderPath("");
2023-08-14 12:55:30 +02:00
if (imagePath !== "" || batchFolderPath !== "") {
setProgress(t("APP.PROGRESS.WAIT_TITLE"));
2023-11-22 16:54:02 +01:00
// Double Upscayl
2022-11-11 21:39:28 +01:00
if (doubleUpscayl) {
2023-11-22 16:54:02 +01:00
window.electron.send<DoubleUpscaylPayload>(COMMAND.DOUBLE_UPSCAYL, {
2022-11-11 21:39:28 +01:00
imagePath,
outputPath,
model,
2022-12-16 17:20:46 +01:00
gpuId: gpuId.length === 0 ? null : gpuId,
saveImageAs,
2023-04-14 12:31:37 +02:00
scale,
2023-11-22 16:54:02 +01:00
noImageProcessing,
2023-11-23 06:39:46 +01:00
compression: compression.toString(),
customWidth: customWidth > 0 ? customWidth.toString() : null,
2024-04-20 17:44:42 +02:00
useCustomWidth,
tileSize,
2022-11-11 21:39:28 +01:00
});
logit("🏁 DOUBLE_UPSCAYL");
2022-11-11 21:39:28 +01:00
} else if (batchMode) {
2023-11-22 16:54:02 +01:00
// Batch Upscayl
2022-11-11 21:39:28 +01:00
setDoubleUpscayl(false);
2023-11-22 16:54:02 +01:00
window.electron.send<BatchUpscaylPayload>(COMMAND.FOLDER_UPSCAYL, {
2022-11-11 21:39:28 +01:00
batchFolderPath,
outputPath,
model,
2022-12-16 17:20:46 +01:00
gpuId: gpuId.length === 0 ? null : gpuId,
saveImageAs,
2023-04-14 12:31:37 +02:00
scale,
2023-11-22 16:54:02 +01:00
noImageProcessing,
2023-11-23 06:39:46 +01:00
compression: compression.toString(),
customWidth: customWidth > 0 ? customWidth.toString() : null,
2024-04-20 17:44:42 +02:00
useCustomWidth,
tileSize,
2022-11-11 21:39:28 +01:00
});
logit("🏁 FOLDER_UPSCAYL");
2022-11-11 21:39:28 +01:00
} else {
2023-11-22 16:54:02 +01:00
// Single Image Upscayl
window.electron.send<ImageUpscaylPayload>(COMMAND.UPSCAYL, {
2022-11-11 21:39:28 +01:00
imagePath,
outputPath,
model,
2022-12-16 17:20:46 +01:00
gpuId: gpuId.length === 0 ? null : gpuId,
saveImageAs,
2023-04-14 12:31:37 +02:00
scale,
2023-08-27 18:11:01 +02:00
overwrite,
2023-11-22 16:54:02 +01:00
noImageProcessing,
2023-11-23 06:39:46 +01:00
compression: compression.toString(),
customWidth: customWidth > 0 ? customWidth.toString() : null,
2024-04-20 17:44:42 +02:00
useCustomWidth,
tileSize,
2022-11-11 21:39:28 +01:00
});
logit("🏁 UPSCAYL");
2022-11-11 21:39:28 +01:00
}
2023-11-22 16:54:02 +01:00
} else {
2024-04-21 16:04:59 +02:00
toast({
title: t("ERRORS.NO_IMAGE_ERROR.TITLE"),
description: t("ERRORS.NO_IMAGE_ERROR.DESCRIPTION"),
2024-04-21 16:04:59 +02:00
});
logit("🚫 No valid image selected");
2022-11-11 21:39:28 +01:00
}
};
2023-04-28 20:21:42 +02:00
const stopHandler = () => {
2023-09-10 19:42:18 +02:00
window.electron.send(COMMAND.STOP);
logit("🛑 Stopping Upscayl");
2023-04-28 20:21:42 +02:00
resetImagePaths();
};
2023-10-15 05:57:11 +02:00
if (isLoading) {
2023-08-30 06:54:16 +02:00
return (
2024-04-24 13:08:27 +02:00
<Logo className="absolute left-1/2 top-1/2 w-36 -translate-x-1/2 -translate-y-1/2 animate-pulse" />
2023-08-30 06:54:16 +02:00
);
}
2022-11-11 21:39:28 +01:00
return (
2022-11-11 22:32:24 +01:00
<div className="flex h-screen w-screen flex-row overflow-hidden bg-base-300">
2024-04-17 18:18:45 +02:00
{/* 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 ">
2024-04-24 13:08:27 +02:00
<Logo className="w-5" />
{t("TITLE")}
2024-04-17 18:18:45 +02:00
</div>
)}
{/* SIDEBAR BUTTON */}
<button
className={cn(
2024-04-22 09:55:44 +02:00
"fixed left-0 top-1/2 z-[999] -translate-y-1/2 rounded-r-full bg-base-100 p-4 ",
2024-04-17 18:18:45 +02:00
showSidebar ? "hidden" : "",
)}
onClick={() => setShowSidebar((prev) => !prev)}
>
2024-04-22 09:55:44 +02:00
<ChevronRightIcon />
2024-04-17 18:18:45 +02:00
</button>
2024-04-18 20:45:12 +02:00
2024-04-17 18:18:45 +02:00
{/* LEFT PANE */}
<div
className={`relative flex h-screen min-w-[350px] max-w-[350px] flex-col bg-base-100 ${showSidebar ? "" : "hidden"}`}
>
<button
2024-04-22 09:55:44 +02:00
className="absolute -right-0 top-1/2 z-[999] -translate-y-1/2 translate-x-1/2 rounded-full bg-base-100 p-4"
2024-04-17 18:18:45 +02:00
onClick={() => setShowSidebar((prev) => !prev)}
>
2024-04-22 09:55:44 +02:00
<ChevronLeftIcon />
2024-04-17 18:18:45 +02:00
</button>
2024-04-18 20:45:12 +02:00
2024-04-17 18:18:45 +02:00
{/* UPSCAYL CLOUD MODAL */}
2023-11-02 16:03:21 +01:00
{featureFlags.SHOW_UPSCAYL_CLOUD_INFO && (
<UpscaylCloudModal
show={showCloudModal}
setShow={setShowCloudModal}
setDontShowCloudModal={setDontShowCloudModal}
/>
)}
2024-04-17 18:18:45 +02:00
{/* MACOS TITLEBAR */}
2023-08-30 06:54:16 +02:00
{window.electron.platform === "mac" && (
2024-02-07 02:23:19 +01:00
<div className="mac-titlebar pt-8"></div>
2023-08-30 06:54:16 +02:00
)}
2022-11-11 21:39:28 +01:00
{/* HEADER */}
2023-08-30 09:58:15 +02:00
<Header version={version} />
2023-11-02 16:03:21 +01:00
{!dontShowCloudModal && featureFlags.SHOW_UPSCAYL_CLOUD_INFO && (
2023-09-03 11:16:48 +02:00
<button
2024-04-18 23:58:47 +02:00
className="mx-5 mb-5 animate-pulse rounded-btn bg-success p-1 text-sm text-slate-50 shadow-lg shadow-success/40"
2023-09-03 11:16:48 +02:00
onClick={() => {
setShowCloudModal(true);
2024-02-07 02:23:19 +01:00
}}
>
{t("INTRO")}
2023-09-03 11:16:48 +02:00
</button>
)}
2023-08-30 07:35:40 +02:00
2024-04-17 18:18:45 +02:00
{/* NEWS DIALOG */}
2023-11-23 10:25:55 +01:00
<NewsModal
show={showNewsModal}
setShow={(val: boolean) => {
setShowNewsModal(val);
setNews((prev) => ({ ...prev, seen: true }));
}}
news={news}
/>
2023-03-18 18:08:50 +01:00
<Tabs selectedTab={selectedTab} setSelectedTab={setSelectedTab} />
2023-08-14 12:55:30 +02:00
2023-03-18 18:08:50 +01:00
{selectedTab === 0 && (
2022-11-23 19:24:30 +01:00
<LeftPaneImageSteps
selectImageHandler={selectImageHandler}
selectFolderHandler={selectFolderHandler}
handleModelChange={handleModelChange}
upscaylHandler={upscaylHandler}
batchMode={batchMode}
setBatchMode={setBatchMode}
imagePath={imagePath}
doubleUpscayl={doubleUpscayl}
setDoubleUpscayl={setDoubleUpscayl}
2022-12-24 08:17:54 +01:00
dimensions={dimensions}
2023-05-01 11:23:11 +02:00
setGpuId={setGpuId}
2023-09-19 17:14:15 +02:00
model={model}
2023-05-01 11:23:11 +02:00
setModel={setModel}
setSaveImageAs={setSaveImageAs}
2022-11-23 19:24:30 +01:00
/>
)}
2023-03-18 18:08:50 +01:00
{selectedTab === 1 && (
<SettingsTab
batchMode={batchMode}
setModel={setModel}
2023-09-13 16:07:45 +02:00
compression={compression}
setCompression={setCompression}
2023-03-18 18:08:50 +01:00
gpuId={gpuId}
setGpuId={setGpuId}
saveImageAs={saveImageAs}
setSaveImageAs={setSaveImageAs}
2023-04-08 08:53:32 +02:00
logData={logData}
2023-08-14 12:55:30 +02:00
os={os}
2023-09-03 11:16:48 +02:00
show={showCloudModal}
setShow={setShowCloudModal}
setDontShowCloudModal={setDontShowCloudModal}
2023-03-18 18:08:50 +01:00
/>
)}
{/* )} */}
2022-11-11 21:39:28 +01:00
<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)}
2023-11-10 14:23:55 +01:00
onDoubleClick={() => {
if (batchMode) {
selectFolderHandler();
} else {
selectImageHandler();
}
}}
2024-02-07 02:23:19 +01:00
onPaste={(e) => handlePaste(e)}
>
2023-08-30 06:54:16 +02:00
{window.electron.platform === "mac" && (
2024-02-07 02:23:19 +01:00
<div className="mac-titlebar absolute top-0 h-8 w-full"></div>
2023-08-30 06:54:16 +02:00
)}
2022-11-11 21:39:28 +01:00
{progress.length > 0 &&
upscaledImagePath.length === 0 &&
2023-08-14 12:55:30 +02:00
upscaledBatchFolderPath.length === 0 ? (
2022-12-02 15:21:42 +01:00
<ProgressBar
batchMode={batchMode}
2022-12-02 15:21:42 +01:00
progress={progress}
doubleUpscaylCounter={doubleUpscaylCounter}
2023-04-28 20:21:42 +02:00
stopHandler={stopHandler}
2022-12-02 15:21:42 +01:00
/>
2022-11-11 21:39:28 +01:00
) : null}
2022-11-25 08:30:03 +01:00
{/* DEFAULT PANE INFO */}
2023-08-14 12:55:30 +02:00
{((!batchMode &&
imagePath.length === 0 &&
2022-11-11 21:39:28 +01:00
upscaledImagePath.length === 0) ||
2023-08-14 12:55:30 +02:00
(batchMode &&
batchFolderPath.length === 0 &&
2023-08-14 12:55:30 +02:00
upscaledBatchFolderPath.length === 0)) && (
<RightPaneInfo version={version} batchMode={batchMode} />
2022-11-11 21:39:28 +01:00
)}
2022-11-25 08:30:03 +01:00
{/* SHOW SELECTED IMAGE */}
2022-11-11 21:39:28 +01:00
{!batchMode &&
upscaledImagePath.length === 0 &&
imagePath.length > 0 && (
2022-12-24 08:40:45 +01:00
<>
<ImageOptions
zoomAmount={zoomAmount}
setZoomAmount={setZoomAmount}
resetImagePaths={resetImagePaths}
hideZoomOptions={true}
/>
<img
src={"file:///" + sanitizePath(imagePath)}
2022-12-24 08:40:45 +01:00
onLoad={(e: any) => {
setDimensions({
width: e.target.naturalWidth,
height: e.target.naturalHeight,
});
}}
draggable="false"
alt=""
2023-10-14 03:00:49 +02:00
className="h-full w-full bg-gradient-to-br from-base-300 to-base-100 object-contain"
2022-12-24 08:40:45 +01:00
/>
</>
2022-11-11 21:39:28 +01:00
)}
2022-11-25 08:30:03 +01:00
{/* BATCH UPSCALE SHOW SELECTED FOLDER */}
2022-11-11 21:39:28 +01:00
{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>{" "}
2023-09-09 15:01:31 +02:00
{batchFolderPath}
2022-11-11 21:39:28 +01:00
</p>
)}
2022-11-25 08:30:03 +01:00
{/* BATCH UPSCALE DONE INFO */}
2022-11-11 21:39:28 +01:00
{batchMode && upscaledBatchFolderPath.length > 0 && (
2024-02-14 07:32:52 +01:00
<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")}
2022-11-11 21:39:28 +01:00
</p>
<button
2024-02-07 02:23:19 +01:00
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")}
2022-11-11 21:39:28 +01:00
</button>
2024-02-14 07:32:52 +01:00
</div>
2022-11-11 21:39:28 +01:00
)}
2024-01-23 09:44:32 +01:00
<ImageOptions
zoomAmount={zoomAmount}
setZoomAmount={setZoomAmount}
resetImagePaths={resetImagePaths}
/>
{!batchMode &&
viewType === "lens" &&
upscaledImagePath &&
imagePath && (
<div
2024-02-07 02:34:06 +01:00
className="group relative h-full w-full overflow-hidden"
2024-02-07 02:23:19 +01:00
onMouseMove={handleMouseMoveCompare}
>
2024-01-23 09:44:32 +01:00
<img
2024-02-07 02:23:19 +01:00
className={`absolute left-0 top-0 h-full w-full object-contain transition-transform group-hover:scale-[${
2024-01-23 09:44:32 +01:00
zoomAmount + "%"
}]`}
src={"file:///" + imagePath}
style={{
backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition,
}}
/>
<div
2024-02-07 02:27:54 +01:00
className={`invisible absolute left-0 top-0 h-full w-full bg-white mix-blend-difference group-hover:visible group-hover:scale-[${
2024-01-23 09:44:32 +01:00
zoomAmount + "%"
}]`}
style={{
clipPath: `circle(${
2024-02-07 02:34:06 +01:00
(lensSize + 2 * (parseInt(zoomAmount) / 100)) /
(parseInt(zoomAmount) / 100)
2024-01-23 09:44:32 +01:00
}px at ${cursorPosition.x}px ${cursorPosition.y}px)`,
backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition,
}}
/>
<img
2024-02-07 02:23:19 +01:00
className={`absolute h-full w-full object-contain transition-transform group-hover:scale-[${
2024-01-23 09:44:32 +01:00
zoomAmount + "%"
}]`}
src={"file:///" + upscaledImagePath}
style={{
clipPath: `circle(${
2024-02-07 02:34:06 +01:00
(lensSize + parseInt(zoomAmount) / 100) /
2024-02-07 02:23:19 +01:00
(parseInt(zoomAmount) / 100)
2024-01-23 09:44:32 +01:00
}px at ${cursorPosition.x}px ${cursorPosition.y}px)`,
2024-02-07 02:23:19 +01:00
backgroundPosition: backgroundPosition,
2024-01-23 09:44:32 +01:00
transformOrigin: backgroundPosition,
}}
/>
</div>
)}
2022-11-25 08:30:03 +01:00
{/* COMPARISON SLIDER */}
2024-01-23 09:44:32 +01:00
{!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")}
2024-01-23 09:44:32 +01:00
</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")}
2024-01-23 09:44:32 +01:00
onMouseMove={handleMouseMove}
style={{
objectFit: "contain",
backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition,
}}
2024-01-23 09:54:08 +01:00
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${zoomAmount}%]`}
2024-01-23 09:44:32 +01:00
/>
</>
}
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")}
2024-01-23 09:44:32 +01:00
</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")}
2024-01-23 09:44:32 +01:00
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"
/>
</>
)}
2022-11-11 21:39:28 +01:00
</div>
</div>
);
};
export default Home;