1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-12-21 03:45:52 +01:00
upscayl/renderer/components/upscayl-tab/config/LeftPaneImageSteps.tsx

385 lines
12 KiB
TypeScript
Raw Normal View History

2023-11-10 12:41:35 +01:00
import { useAtom, useAtomValue } from "jotai";
2024-04-17 18:18:45 +02:00
import React, { useCallback, useEffect, useState } from "react";
import { Tooltip } from "react-tooltip";
2022-12-08 04:25:26 +01:00
import { themeChange } from "theme-change";
2023-07-22 13:07:53 +02:00
import { modelsListAtom } from "../../../atoms/modelsListAtom";
import useLog from "../../hooks/useLog";
2023-09-19 16:51:38 +02:00
import {
noImageProcessingAtom,
2024-04-09 20:11:24 +02:00
savedOutputPathAtom,
2023-11-10 12:41:35 +01:00
progressAtom,
2024-02-14 07:32:52 +01:00
rememberOutputFolderAtom,
2023-09-19 16:51:38 +02:00
scaleAtom,
} from "../../../atoms/userSettingsAtom";
2023-11-02 16:03:21 +01:00
import { featureFlags } from "@common/feature-flags";
2024-01-15 10:25:29 +01:00
import getModelScale from "@common/check-model-scale";
2024-02-14 07:32:52 +01:00
import COMMAND from "@common/commands";
2024-04-17 18:18:45 +02:00
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { ChevronsUpDownIcon } from "lucide-react";
2022-11-11 21:39:28 +01:00
2022-11-15 15:54:06 +01:00
interface IProps {
selectImageHandler: () => Promise<void>;
selectFolderHandler: () => Promise<void>;
handleModelChange: (e: any) => void;
upscaylHandler: () => Promise<void>;
batchMode: boolean;
2023-03-12 08:41:43 +01:00
setBatchMode: React.Dispatch<React.SetStateAction<boolean>>;
2022-11-15 15:54:06 +01:00
imagePath: string;
doubleUpscayl: boolean;
2023-03-12 08:41:43 +01:00
setDoubleUpscayl: React.Dispatch<React.SetStateAction<boolean>>;
2022-12-24 08:17:54 +01:00
dimensions: {
width: number | null;
height: number | null;
};
2023-05-01 11:23:11 +02:00
setSaveImageAs: React.Dispatch<React.SetStateAction<string>>;
2023-09-19 17:14:15 +02:00
model: string;
2023-05-01 11:23:11 +02:00
setModel: React.Dispatch<React.SetStateAction<string>>;
setGpuId: React.Dispatch<React.SetStateAction<string>>;
2022-11-15 15:54:06 +01:00
}
2022-11-23 19:24:30 +01:00
function LeftPaneImageSteps({
2022-11-15 15:54:06 +01:00
selectImageHandler,
selectFolderHandler,
handleModelChange,
upscaylHandler,
batchMode,
setBatchMode,
imagePath,
doubleUpscayl,
setDoubleUpscayl,
2022-12-24 08:17:54 +01:00
dimensions,
2023-05-01 11:23:11 +02:00
setSaveImageAs,
2023-09-19 17:14:15 +02:00
model,
2023-05-01 11:23:11 +02:00
setModel,
setGpuId,
2022-11-15 15:54:06 +01:00
}: IProps) {
2022-12-24 09:45:15 +01:00
const [currentModel, setCurrentModel] = useState<{
label: string;
value: string;
}>({
label: null,
value: null,
});
const modelOptions = useAtomValue(modelsListAtom);
2023-08-30 07:35:40 +02:00
const scale = useAtomValue(scaleAtom);
2023-09-19 16:51:38 +02:00
const noImageProcessing = useAtomValue(noImageProcessingAtom);
2024-04-09 20:11:24 +02:00
const [outputPath, setOutputPath] = useAtom(savedOutputPathAtom);
2023-11-10 12:41:35 +01:00
const [progress, setProgress] = useAtom(progressAtom);
2024-02-14 07:32:52 +01:00
const rememberOutputFolder = useAtomValue(rememberOutputFolderAtom);
2024-04-17 18:18:45 +02:00
const [open, setOpen] = React.useState(false);
2023-03-12 08:41:43 +01:00
2024-02-07 02:46:01 +01:00
const [targetWidth, setTargetWidth] = useState<number>(null);
const [targetHeight, setTargetHeight] = useState<number>(null);
2023-05-01 11:23:11 +02:00
const { logit } = useLog();
2024-02-14 07:32:52 +01:00
const outputHandler = async () => {
var path = await window.electron.invoke(COMMAND.SELECT_FOLDER);
if (path !== null) {
logit("🗂 Setting Output Path: ", path);
setOutputPath(path);
} else {
setOutputPath(null);
}
};
2023-05-01 11:23:11 +02:00
useEffect(() => {
themeChange(false);
if (!localStorage.getItem("saveImageAs")) {
logit("⚙️ Setting saveImageAs to png");
2023-05-01 11:23:11 +02:00
localStorage.setItem("saveImageAs", "png");
} else {
const currentlySavedImageFormat = localStorage.getItem("saveImageAs");
logit(
2023-09-13 16:07:45 +02:00
"⚙️ Getting saveImageAs from localStorage: ",
2024-02-07 02:46:01 +01:00
currentlySavedImageFormat,
2023-05-01 11:23:11 +02:00
);
setSaveImageAs(currentlySavedImageFormat);
}
if (!localStorage.getItem("model")) {
setCurrentModel(modelOptions[0]);
setModel(modelOptions[0].value);
localStorage.setItem("model", JSON.stringify(modelOptions[0]));
logit("🔀 Setting model to", modelOptions[0].value);
2023-05-01 11:23:11 +02:00
} else {
const currentlySavedModel = JSON.parse(
2024-02-07 02:46:01 +01:00
localStorage.getItem("model"),
2023-05-01 11:23:11 +02:00
) as (typeof modelOptions)[0];
setCurrentModel(currentlySavedModel);
setModel(currentlySavedModel.value);
logit(
2023-09-13 16:07:45 +02:00
"⚙️ Getting model from localStorage: ",
2024-02-07 02:46:01 +01:00
JSON.stringify(currentlySavedModel),
2023-05-01 11:23:11 +02:00
);
}
if (!localStorage.getItem("gpuId")) {
localStorage.setItem("gpuId", "");
logit("⚙️ Setting gpuId to empty string");
2023-05-01 11:23:11 +02:00
} else {
const currentlySavedGpuId = localStorage.getItem("gpuId");
setGpuId(currentlySavedGpuId);
2023-09-13 16:07:45 +02:00
logit("⚙️ Getting gpuId from localStorage: ", currentlySavedGpuId);
2023-05-01 11:23:11 +02:00
}
}, []);
useEffect(() => {
logit("🔀 Setting model to", currentModel.value);
2023-05-01 11:23:11 +02:00
}, [currentModel]);
2024-02-07 02:46:01 +01:00
useEffect(() => {
setTargetWidth(getUpscaleResolution().width);
setTargetHeight(getUpscaleResolution().height);
}, [dimensions.width, dimensions.height, doubleUpscayl, scale]);
2023-08-30 07:35:40 +02:00
const getUpscaleResolution = useCallback(() => {
2023-06-03 02:49:13 +02:00
const newDimensions = {
width: dimensions.width,
height: dimensions.height,
};
2023-08-30 07:35:40 +02:00
2023-09-19 16:51:38 +02:00
let doubleScale = parseInt(scale) * parseInt(scale);
let singleScale = parseInt(scale);
if (noImageProcessing) {
2024-01-15 10:25:29 +01:00
let initialScale = parseInt(getModelScale(model));
2023-09-19 16:51:38 +02:00
doubleScale = initialScale * initialScale;
singleScale = initialScale;
}
2023-08-30 07:35:40 +02:00
2023-06-03 02:49:13 +02:00
if (doubleUpscayl) {
2023-08-30 07:35:40 +02:00
const newWidth = dimensions.width * doubleScale;
const newHeight = dimensions.height * doubleScale;
if (newWidth < 32768 || newHeight < 32768) {
newDimensions.width = newWidth;
newDimensions.height = newHeight;
} else {
newDimensions.width = 32384;
newDimensions.height = 32384;
}
2023-06-03 02:49:13 +02:00
} else {
2023-08-30 07:35:40 +02:00
newDimensions.width = dimensions.width * singleScale;
newDimensions.height = dimensions.height * singleScale;
2023-06-03 02:49:13 +02:00
}
return newDimensions;
2023-08-30 07:35:40 +02:00
}, [dimensions.width, dimensions.height, doubleUpscayl, scale]);
2023-06-03 02:49:13 +02:00
2022-11-11 21:39:28 +01:00
return (
2023-08-30 06:54:16 +02:00
<div
2024-02-07 02:46:01 +01:00
className={`animate-step-in animate flex h-screen flex-col gap-7 overflow-y-auto overflow-x-hidden p-5`}
>
2022-11-11 21:39:28 +01:00
{/* BATCH OPTION */}
2022-11-11 22:32:24 +01:00
<div className="flex flex-row items-center gap-2">
<input
type="checkbox"
2022-11-15 15:42:20 +01:00
className="toggle"
2023-04-15 07:00:19 +02:00
defaultChecked={batchMode}
2023-11-10 12:41:35 +01:00
onClick={() => {
2024-02-14 07:32:52 +01:00
if (!rememberOutputFolder) {
setOutputPath("");
}
2023-11-10 12:41:35 +01:00
setProgress("");
setBatchMode((oldValue) => !oldValue);
2024-02-07 02:46:01 +01:00
}}
></input>
2022-11-23 19:24:30 +01:00
<p
2023-08-30 06:54:16 +02:00
className="mr-1 inline-block cursor-help text-sm"
data-tooltip-id="tooltip"
2024-02-07 02:46:01 +01:00
data-tooltip-content="This will let you Upscayl all files in a folder at once"
>
Batch Upscayl
2022-11-23 19:24:30 +01:00
</p>
2022-11-11 21:39:28 +01:00
</div>
{/* STEP 1 */}
<div data-tooltip-id="tooltip" data-tooltip-content={imagePath}>
2022-11-11 21:39:28 +01:00
<p className="step-heading">Step 1</p>
<button
2024-02-07 02:46:01 +01:00
className="btn btn-primary"
onClick={!batchMode ? selectImageHandler : selectFolderHandler}
>
2022-11-15 15:54:06 +01:00
Select {batchMode ? "Folder" : "Image"}
2022-11-11 21:39:28 +01:00
</button>
</div>
{/* STEP 2 */}
2023-11-10 12:41:35 +01:00
<div className="animate-step-in group">
2022-11-11 21:39:28 +01:00
<p className="step-heading">Step 2</p>
2023-09-09 13:03:16 +02:00
<p className="mb-2 text-sm">Select Model</p>
2022-11-11 21:39:28 +01:00
2024-04-17 18:18:45 +02:00
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="default"
role="combobox"
aria-expanded={open}
className="w-[200px] justify-between truncate transition-all group-hover:w-full group-active:w-full focus:w-full"
>
<p className="truncate">
{currentModel.value
? modelOptions.find(
(modelOption) => modelOption.value === currentModel.value,
)?.label
: "Select model..."}
</p>
<ChevronsUpDownIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent>
<Command>
<CommandInput placeholder="Search framework..." className="h-9" />
<CommandEmpty>No framework found.</CommandEmpty>
<CommandGroup>
{modelOptions?.map(({ value, label }) => {
return (
<CommandItem
key={value.toString()}
value={value.toString()}
>
{label.toString()}
</CommandItem>
);
})}
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
{/*
2022-11-11 21:39:28 +01:00
<Select
options={modelOptions}
components={{
IndicatorSeparator: () => null,
DropdownIndicator: () => null,
}}
2022-12-27 07:45:16 +01:00
onChange={(e) => {
handleModelChange(e);
setCurrentModel({ label: e.label, value: e.value });
}}
2024-02-07 02:46:01 +01:00
className="react-select-container transition-all group-hover:w-full group-active:w-full focus:w-full"
2022-11-11 21:39:28 +01:00
classNamePrefix="react-select"
2022-12-24 09:45:15 +01:00
value={currentModel}
2024-04-17 18:18:45 +02:00
/> */}
2022-11-11 21:39:28 +01:00
2023-03-18 13:33:17 +01:00
{!batchMode && (
2022-11-23 19:24:30 +01:00
<div className="mt-4 flex items-center gap-1">
2022-11-11 21:39:28 +01:00
<input
type="checkbox"
2022-11-11 22:32:24 +01:00
className="checkbox"
2022-11-15 15:54:06 +01:00
checked={doubleUpscayl}
2022-11-11 21:39:28 +01:00
onChange={(e) => {
if (e.target.checked) {
2022-11-15 15:54:06 +01:00
setDoubleUpscayl(true);
2022-11-11 21:39:28 +01:00
} else {
2022-11-15 15:54:06 +01:00
setDoubleUpscayl(false);
2022-11-11 21:39:28 +01:00
}
}}
/>
<p
2022-11-11 22:32:24 +01:00
className="cursor-pointer text-sm"
2022-11-11 21:39:28 +01:00
onClick={(e) => {
2022-11-15 15:54:06 +01:00
setDoubleUpscayl(!doubleUpscayl);
2024-02-07 02:46:01 +01:00
}}
>
2022-11-11 21:39:28 +01:00
Double Upscayl
</p>
2022-11-23 19:24:30 +01:00
<button
2024-02-07 02:46:01 +01:00
className="badge badge-neutral badge-sm cursor-help"
data-tooltip-id="tooltip"
2024-02-07 02:46:01 +01:00
data-tooltip-content="Enable this option to get a 16x upscayl (we just run upscayl twice). Note that this may not always work properly with all images, for example, images with really large resolutions."
>
?
2022-11-23 19:24:30 +01:00
</button>
2022-11-11 21:39:28 +01:00
</div>
)}
</div>
{/* STEP 3 */}
<div
className="animate-step-in"
data-tooltip-content={outputPath}
2024-02-07 02:46:01 +01:00
data-tooltip-id="tooltip"
>
2024-01-15 14:13:16 +01:00
<div className="flex flex-col pb-2">
<div className="step-heading flex items-center gap-2">
<span className="leading-none">Step 3</span>
{featureFlags.APP_STORE_BUILD && (
<button
2024-02-07 02:46:01 +01:00
className="badge badge-outline badge-sm cursor-pointer"
2024-01-15 14:13:16 +01:00
onClick={() =>
alert(
2024-02-07 02:46:01 +01:00
"Due to MacOS App Store security restrictions, Upscayl requires you to select an output folder everytime you start it.\n\nTo avoid this, you can permanently save a default output folder in the Upscayl 'Settings' tab.",
2024-01-15 14:13:16 +01:00
)
2024-02-07 02:46:01 +01:00
}
>
2024-01-15 14:13:16 +01:00
?
</button>
)}
</div>
2023-11-10 12:41:35 +01:00
{!outputPath && featureFlags.APP_STORE_BUILD && (
2023-11-02 16:03:21 +01:00
<div className="text-xs">
2024-02-07 02:46:01 +01:00
<span className="rounded-btn bg-base-200 px-2 font-medium uppercase text-base-content/50">
2023-11-02 16:03:21 +01:00
Not selected
</span>
</div>
)}
</div>
{!batchMode && !featureFlags.APP_STORE_BUILD && (
<p className="mb-2 text-sm">
Defaults to {!batchMode ? "Image's" : "Folder's"} path
</p>
)}
2024-02-07 02:46:01 +01:00
<button className="btn btn-primary" onClick={outputHandler}>
2022-11-11 21:39:28 +01:00
Set Output Folder
</button>
</div>
{/* STEP 4 */}
<div className="animate-step-in">
<p className="step-heading">Step 4</p>
2022-12-24 08:17:54 +01:00
{dimensions.width && dimensions.height && (
<p className="mb-2 text-sm">
2024-02-08 15:57:35 +01:00
Upscayl from{" "}
2022-12-24 08:17:54 +01:00
<span className="font-bold">
{dimensions.width}x{dimensions.height}
</span>{" "}
2024-02-08 15:57:35 +01:00
to{" "}
<span className="font-bold">
2023-06-03 02:49:50 +02:00
{getUpscaleResolution().width}x{getUpscaleResolution().height}
2024-02-08 15:57:35 +01:00
</span>
2022-12-24 08:17:54 +01:00
</p>
)}
2022-11-11 21:39:28 +01:00
<button
2024-02-07 02:46:01 +01:00
className="btn btn-accent"
2023-11-10 12:41:35 +01:00
onClick={
progress.length > 0 || !outputPath
? () => alert("Please select an output folder first")
: upscaylHandler
2024-02-07 02:46:01 +01:00
}
>
2022-11-15 15:54:06 +01:00
{progress.length > 0 ? "Upscayling⏳" : "Upscayl"}
2022-11-11 21:39:28 +01:00
</button>
</div>
2022-11-23 19:24:30 +01:00
<Tooltip className="z-50 max-w-sm" id="tooltip" />
2022-11-11 21:39:28 +01:00
</div>
);
}
2022-11-23 19:24:30 +01:00
export default LeftPaneImageSteps;