diff --git a/app/components/ConvertButton/ConvertButton.tsx b/app/components/ConvertButton/ConvertButton.tsx index 3d1176f..55f1553 100644 --- a/app/components/ConvertButton/ConvertButton.tsx +++ b/app/components/ConvertButton/ConvertButton.tsx @@ -1,6 +1,6 @@ "use client"; -import { useAtom } from "jotai"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { filePathsAtom, fileInfosAtom, @@ -16,15 +16,15 @@ import "@ant-design/v5-patch-for-react-19"; import { useState } from "react"; export default function ConvertButton() { - const [filePaths] = useAtom(filePathsAtom); - const [fileInfos] = useAtom(fileInfosAtom); - const [extensionType] = useAtom(extensionTypeAtom); - const [quality] = useAtom(qualityAtom); + const filePaths = useAtomValue(filePathsAtom); + const fileInfos = useAtomValue(fileInfosAtom); + const extensionType = useAtomValue(extensionTypeAtom); + const quality = useAtomValue(qualityAtom); const [isProcessing, setIsProcessing] = useAtom(isProcessingAtom); - const [, setProcessedFilePaths] = useAtom(processedFilePathsAtom); - const [, setTabSelected] = useAtom(tabSelectedAtom); + const setProcessedFilePaths = useSetAtom(processedFilePathsAtom); + const setTabSelected = useSetAtom(tabSelectedAtom); const [dialog, setDialog] = useState(null); - const [, setOutputTempDir] = useAtom(outputTempDirAtom); + const setOutputTempDir = useSetAtom(outputTempDirAtom); const handleConvert = async () => { const errorDialog = await convert( diff --git a/app/components/Dropzone/Dropzone.tsx b/app/components/Dropzone/Dropzone.tsx index ed6e2c5..39cc23e 100644 --- a/app/components/Dropzone/Dropzone.tsx +++ b/app/components/Dropzone/Dropzone.tsx @@ -1,13 +1,13 @@ "use client"; import { useEffect, useState } from "react"; -import { useAtom } from "jotai"; +import { useSetAtom } from "jotai"; import { filePathsAtom, tabSelectedAtom } from "../../lib/atom"; import { WarningDialog, ErrorDialog } from "../Dialog/Dialog"; import { listen } from "@tauri-apps/api/event"; export default function Dropzone() { - const [, setFilePaths] = useAtom(filePathsAtom); - const [, setTabSelected] = useAtom(tabSelectedAtom); + const setFilePaths = useSetAtom(filePathsAtom); + const setTabSelected = useSetAtom(tabSelectedAtom); const [warningModalOpen, setWarningModalOpen] = useState(false); const [errorModalOpen, setErrorModalOpen] = useState(false); const [extensions, setExtensions] = useState([]); diff --git a/app/components/InputTab/InputNavMenu.tsx b/app/components/InputTab/InputNavMenu.tsx index 2fcbc70..c8692ca 100644 --- a/app/components/InputTab/InputNavMenu.tsx +++ b/app/components/InputTab/InputNavMenu.tsx @@ -2,12 +2,12 @@ import "@ant-design/v5-patch-for-react-19"; import FileDialog from "../FileDialog/FileDialog"; import { Button } from "antd"; import { DeleteOutlined } from "@ant-design/icons"; -import { useAtom } from "jotai"; +import { useSetAtom } from "jotai"; import { filePathsAtom, fileInfosAtom } from "../../lib/atom"; export default function InputNubMenu() { - const [, setFilePaths] = useAtom(filePathsAtom); - const [, setFileInfos] = useAtom(fileInfosAtom); + const setFilePaths = useSetAtom(filePathsAtom); + const setFileInfos = useSetAtom(fileInfosAtom); const removeAll = () => { setFilePaths([]); diff --git a/app/components/InputTab/InputTab.tsx b/app/components/InputTab/InputTab.tsx index 7c9de41..38468cc 100644 --- a/app/components/InputTab/InputTab.tsx +++ b/app/components/InputTab/InputTab.tsx @@ -1,15 +1,15 @@ "use client"; import SelectFiles from "../SelectFiles/SelectFiles"; -import { useAtom } from "jotai"; +import { useAtomValue } from "jotai"; import { tabSelectedAtom, filePathsAtom } from "../../lib/atom"; import InputNubMenu from "./InputNavMenu"; import Null from "./Null"; import Dropzone from "../Dropzone/Dropzone"; export default function InputTab() { - const [tabSelected] = useAtom(tabSelectedAtom); - const [filePaths] = useAtom(filePathsAtom); + const tabSelected = useAtomValue(tabSelectedAtom); + const filePaths = useAtomValue(filePathsAtom); return (
(null); - const [outputTempDir,] = useAtom(outputTempDirAtom); + const outputTempDir = useAtomValue(outputTempDirAtom); const handleSaveAll = async () => { const result = await saveAll(setIsSaving, processedFilePathsSorted, setDialog); diff --git a/app/components/OutputTab/OutputTab.tsx b/app/components/OutputTab/OutputTab.tsx index c5699a1..626cb2e 100644 --- a/app/components/OutputTab/OutputTab.tsx +++ b/app/components/OutputTab/OutputTab.tsx @@ -1,12 +1,12 @@ "use client"; -import { useAtom } from "jotai"; +import { useAtomValue } from "jotai"; import { tabSelectedAtom } from "../../lib/atom"; import ProcessedFiles from "../ProcessedFiles/ProcessedFiles"; import OutputNavMenu from "./OutputNavMenu"; export default function OutputTab() { - const [tabSelected] = useAtom(tabSelectedAtom); + const tabSelected = useAtomValue(tabSelectedAtom); return (
(null); @@ -43,6 +43,12 @@ export default function File({ }; handleImageLoad(filePaths[index]); + + return () => { + if (imageSrc) { + URL.revokeObjectURL(imageSrc); + } + }; }, [processedFileInfo.file_name_with_extension]); const compressionRate = getCompressionRate(processedFileInfo); diff --git a/app/components/ProcessedFiles/ProcessedFiles.tsx b/app/components/ProcessedFiles/ProcessedFiles.tsx index c1d952e..95f521f 100644 --- a/app/components/ProcessedFiles/ProcessedFiles.tsx +++ b/app/components/ProcessedFiles/ProcessedFiles.tsx @@ -1,6 +1,6 @@ "use client"; -import { useAtom } from "jotai"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { fileInfosAtom, processedFilePathsAtom, @@ -14,15 +14,15 @@ import { getProcessedFileInfo } from "../SelectFiles/utils"; import type { ProcessedFileInfo } from "@/app/index.d"; export default function ProcessedFiles() { - const [fileInfos] = useAtom(fileInfosAtom); - const [processedFilePaths] = useAtom(processedFilePathsAtom); + const fileInfos = useAtomValue(fileInfosAtom); + const processedFilePaths = useAtomValue(processedFilePathsAtom); const [processedFileInfos, setProcessedFileInfos] = useAtom( processedFileInfosAtom ); const [processedFilePathsSorted, setProcessedFilePathsSorted] = useAtom( processedFilePathsSortedAtom ); - const [, setCheckboxSelected] = useAtom(checkboxSelectedAtom); + const setCheckboxSelected = useSetAtom(checkboxSelectedAtom); useEffect(() => { const fetchProcessedInfos = async () => { diff --git a/app/components/SelectFiles/File.tsx b/app/components/SelectFiles/File.tsx index afacb7d..e694c0d 100644 --- a/app/components/SelectFiles/File.tsx +++ b/app/components/SelectFiles/File.tsx @@ -2,7 +2,7 @@ import { FileProps } from "./index.d"; import { Button } from "antd"; import { DeleteOutlined } from "@ant-design/icons"; -import { useAtom } from "jotai"; +import { useAtom, useSetAtom } from "jotai"; import { filePathsAtom, fileInfosAtom } from "../../lib/atom"; import { useState, useEffect } from "react"; import { readFile } from "@tauri-apps/plugin-fs"; @@ -10,7 +10,7 @@ import "@ant-design/v5-patch-for-react-19"; export default function File({ fileInfo, index }: FileProps) { const [filePaths, setFilePaths] = useAtom(filePathsAtom); - const [, setFileInfos] = useAtom(fileInfosAtom); + const setFileInfos = useSetAtom(fileInfosAtom); const [imageSrc, setImageSrc] = useState(null); useEffect(() => { @@ -26,6 +26,12 @@ export default function File({ fileInfo, index }: FileProps) { }; handleImageLoad(filePaths[index]); + + return () => { + if (imageSrc) { + URL.revokeObjectURL(imageSrc); + } + }; }, [fileInfo.file_name_with_extension]); const extension = diff --git a/app/components/SelectFiles/SelectFiles.tsx b/app/components/SelectFiles/SelectFiles.tsx index b5a9ef6..7f28360 100644 --- a/app/components/SelectFiles/SelectFiles.tsx +++ b/app/components/SelectFiles/SelectFiles.tsx @@ -1,6 +1,6 @@ "use client"; -import { useAtom } from "jotai"; +import { useAtom, useAtomValue } from "jotai"; import { filePathsAtom, fileInfosAtom } from "@/app/lib/atom"; import { FileInfo } from "@/app/index.d"; import { useEffect } from "react"; @@ -9,7 +9,7 @@ import { getFileInfo } from "./utils"; import { readFileAsync } from "../FileDialog/utils"; export default function SelectFiles() { - const [filePaths] = useAtom(filePathsAtom); + const filePaths = useAtomValue(filePathsAtom); const [fileInfos, setFileInfos] = useAtom(fileInfosAtom); useEffect(() => { diff --git a/app/components/WindowMenu/ContextMenu/FileMenu.tsx b/app/components/WindowMenu/ContextMenu/FileMenu.tsx index 046a43d..4701c7f 100644 --- a/app/components/WindowMenu/ContextMenu/FileMenu.tsx +++ b/app/components/WindowMenu/ContextMenu/FileMenu.tsx @@ -2,7 +2,7 @@ import type { MenuProps } from "antd"; import { Dropdown } from "antd"; -import { useAtom } from "jotai"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { fileInfosAtom, filePathsAtom, @@ -53,7 +53,7 @@ const items: MenuProps["items"] = [ export default function FileMenu() { const [filePaths, setFilePaths] = useAtom(filePathsAtom); - const [isFocused] = useAtom(isFocusedAtom); + const isFocused = useAtomValue(isFocusedAtom); const fileButtonRef = useRef(null); const [fileInfos, setFileInfos] = useAtom(fileInfosAtom); const [tabSelected, setTabSelected] = useAtom(tabSelectedAtom); @@ -61,13 +61,13 @@ export default function FileMenu() { processedFilePathsSortedAtom ); const [checkboxSelected, setCheckboxSelected] = useAtom(checkboxSelectedAtom); - const [, setProcessedFilePaths] = useAtom(processedFilePathsAtom); + const setProcessedFilePaths = useSetAtom(processedFilePathsAtom); const [isSaving, setIsSaving] = useAtom(isSavingAtom); - const [quality] = useAtom(qualityAtom); - const [extensionType] = useAtom(extensionTypeAtom); + const quality = useAtomValue(qualityAtom); + const extensionType = useAtomValue(extensionTypeAtom); const [isProcessing, setIsProcessing] = useAtom(isProcessingAtom); - const [, setDialog] = useAtom(windowMenuDialogAtom); - const [, setOutputTempDir] = useAtom(outputTempDirAtom); + const setDialog = useSetAtom(windowMenuDialogAtom); + const setOutputTempDir = useSetAtom(outputTempDirAtom); const handleConvert = async () => { const result = await convert( @@ -224,13 +224,13 @@ function FileOpen(): React.ReactNode { function FileRemoveAll(): React.ReactNode { const [filePaths, setFilePaths] = useAtom(filePathsAtom); - const [tabSelected] = useAtom(tabSelectedAtom); - const [, setFileInfos] = useAtom(fileInfosAtom); + const tabSelected = useAtomValue(tabSelectedAtom); + const setFileInfos = useSetAtom(fileInfosAtom); const [processedFilePathsSorted, setProcessedFilePathsSorted] = useAtom( processedFilePathsSortedAtom ); - const [, setCheckboxSelected] = useAtom(checkboxSelectedAtom); - const [, setProcessedFilePaths] = useAtom(processedFilePathsAtom); + const setCheckboxSelected = useSetAtom(checkboxSelectedAtom); + const setProcessedFilePaths = useSetAtom(processedFilePathsAtom); function removeAll() { setFilePaths([]); @@ -283,8 +283,8 @@ function FileRemoveAll(): React.ReactNode { function FileSaveAll(): React.ReactNode { const [isSaving, setIsSaving] = useState(false); - const [processedFilePathsSorted] = useAtom(processedFilePathsSortedAtom); - const [, setDialog] = useAtom(windowMenuDialogAtom); + const processedFilePathsSorted = useAtomValue(processedFilePathsSortedAtom); + const setDialog = useSetAtom(windowMenuDialogAtom); const handleSaveAll = async () => { const result = await saveAll( setIsSaving, @@ -323,9 +323,9 @@ function FileSaveAll(): React.ReactNode { function FileSaveSelected(): React.ReactNode { const [isSaving, setIsSaving] = useState(false); - const [processedFilePathsSorted] = useAtom(processedFilePathsSortedAtom); - const [checkboxSelected] = useAtom(checkboxSelectedAtom); - const [, setDialog] = useAtom(windowMenuDialogAtom); + const processedFilePathsSorted = useAtomValue(processedFilePathsSortedAtom); + const checkboxSelected = useAtomValue(checkboxSelectedAtom); + const setDialog = useSetAtom(windowMenuDialogAtom); const handleSaveSelected = async () => { const result = await saveSelected( setIsSaving, @@ -365,14 +365,14 @@ function FileSaveSelected(): React.ReactNode { function FileConvert(): React.ReactNode { const [isProcessing, setIsProcessing] = useAtom(isProcessingAtom); - const [, setProcessedFilePaths] = useAtom(processedFilePathsAtom); - const [, setDialog] = useAtom(windowMenuDialogAtom); - const [filePaths] = useAtom(filePathsAtom); - const [fileInfos] = useAtom(fileInfosAtom); - const [quality] = useAtom(qualityAtom); - const [extensionType] = useAtom(extensionTypeAtom); - const [, setTabSelected] = useAtom(tabSelectedAtom); - const [, setOutputTempDir] = useAtom(outputTempDirAtom); + const setProcessedFilePaths = useSetAtom(processedFilePathsAtom); + const setDialog = useSetAtom(windowMenuDialogAtom); + const filePaths = useAtomValue(filePathsAtom); + const fileInfos = useAtomValue(fileInfosAtom); + const quality = useAtomValue(qualityAtom); + const extensionType = useAtomValue(extensionTypeAtom); + const setTabSelected = useSetAtom(tabSelectedAtom); + const setOutputTempDir = useSetAtom(outputTempDirAtom); const handleConvert = async () => { const result = await convert( setIsProcessing, diff --git a/app/components/WindowMenu/ContextMenu/HelpMenu.tsx b/app/components/WindowMenu/ContextMenu/HelpMenu.tsx index d8eb645..cc32f40 100644 --- a/app/components/WindowMenu/ContextMenu/HelpMenu.tsx +++ b/app/components/WindowMenu/ContextMenu/HelpMenu.tsx @@ -2,7 +2,7 @@ import type { MenuProps } from "antd"; import { Dropdown } from "antd"; -import { useAtom } from "jotai"; +import { useAtomValue, useSetAtom } from "jotai"; import { isFocusedAtom, isLicenseDialogOpenAtom, @@ -21,9 +21,9 @@ const items: MenuProps["items"] = [ ]; export default function HelpMenu() { - const [isFocused] = useAtom(isFocusedAtom); - const [isProcessing] = useAtom(isProcessingAtom); - const [isSaving] = useAtom(isSavingAtom); + const isFocused = useAtomValue(isFocusedAtom); + const isProcessing = useAtomValue(isProcessingAtom); + const isSaving = useAtomValue(isSavingAtom); const helpButtonRef = useRef(null); useEffect(() => { const handleKeyDownSelectShortcut = async (event: KeyboardEvent) => { @@ -57,7 +57,7 @@ export default function HelpMenu() { } function Help(): React.ReactNode { - const [, setIsLicenseDialogOpen] = useAtom(isLicenseDialogOpenAtom); + const setIsLicenseDialogOpen = useSetAtom(isLicenseDialogOpenAtom); return ( <>