From f1c7f6dc99f39e196adabd3d165e8dd7343cd6ab Mon Sep 17 00:00:00 2001 From: Qing Date: Sat, 7 Jan 2023 20:51:05 +0800 Subject: [PATCH] add image output tab in file manager --- lama_cleaner/app/src/adapters/inpainting.ts | 8 +- .../components/FileManager/FileManager.scss | 65 ++++++- .../components/FileManager/FileManager.tsx | 170 ++++++++++-------- .../app/src/components/Settings/Settings.scss | 67 ------- .../src/components/SidePanel/SidePanel.tsx | 2 +- lama_cleaner/app/src/components/Workspace.tsx | 4 +- lama_cleaner/file_manager/file_manager.py | 17 +- lama_cleaner/server.py | 29 +-- 8 files changed, 201 insertions(+), 161 deletions(-) diff --git a/lama_cleaner/app/src/adapters/inpainting.ts b/lama_cleaner/app/src/adapters/inpainting.ts index b6e9e3e..74d0656 100644 --- a/lama_cleaner/app/src/adapters/inpainting.ts +++ b/lama_cleaner/app/src/adapters/inpainting.ts @@ -172,9 +172,9 @@ export async function postInteractiveSeg( } } -export async function getMediaFile(filename: string) { +export async function getMediaFile(tab: string, filename: string) { const res = await fetch( - `${API_ENDPOINT}/media/${encodeURIComponent(filename)}`, + `${API_ENDPOINT}/media/${tab}/${encodeURIComponent(filename)}`, { method: 'GET', } @@ -188,8 +188,8 @@ export async function getMediaFile(filename: string) { throw new Error(errMsg) } -export async function getMedias() { - const res = await fetch(`${API_ENDPOINT}/medias`, { +export async function getMedias(tab: string) { + const res = await fetch(`${API_ENDPOINT}/medias/${tab}`, { method: 'GET', }) if (res.ok) { diff --git a/lama_cleaner/app/src/components/FileManager/FileManager.scss b/lama_cleaner/app/src/components/FileManager/FileManager.scss index e844108..0c7fea8 100644 --- a/lama_cleaner/app/src/components/FileManager/FileManager.scss +++ b/lama_cleaner/app/src/components/FileManager/FileManager.scss @@ -91,7 +91,7 @@ padding-left: 30px; height: 32px; border: 1px solid var(--border-color); - border-radius: 8px; + border-radius: 12px; } .sort-btn-inactive { @@ -99,3 +99,66 @@ opacity: 0.5; } } + +/* reset */ +button, +fieldset, +input { + all: unset; +} + +.TabsRoot { + display: flex; + flex-direction: column; + gap: 8px; + background-color: var(--page-bg); + align-self: flex-start; +} + +.TabsList { + display: flex; + flex-direction: row; + gap: 6px; + justify-content: flex-start; + border: 1px solid var(--border-color); + border-radius: 12px; + background-color: var(--page-bg); + padding: 4px; +} + +.TabsTrigger { + font-family: inherit; + background-color: white; + padding: 8px; + display: flex; + align-items: center; + justify-content: flex-start; + font-size: 15px; + line-height: 1; + color: var(--modal-text-color); + user-select: none; + background-color: var(--page-bg); + border-radius: 8px; +} +.TabsTrigger:hover { + background-color: var(--tabs-active-color); +} +.TabsTrigger[data-state='active'] { + background-color: var(--tabs-active-color); +} +.TabsTrigger:focus { + position: relative; +} + +.TabsContent { + background-color: white; + outline: none; + background-color: var(--page-bg); + width: 100%; +} + +.TabsContent[data-state='active'] { + display: flex; + flex-direction: column; + gap: 14px; +} diff --git a/lama_cleaner/app/src/components/FileManager/FileManager.tsx b/lama_cleaner/app/src/components/FileManager/FileManager.tsx index 75f556f..225f2bb 100644 --- a/lama_cleaner/app/src/components/FileManager/FileManager.tsx +++ b/lama_cleaner/app/src/components/FileManager/FileManager.tsx @@ -8,6 +8,7 @@ import React, { FormEvent, } from 'react' import _ from 'lodash' +import * as Tabs from '@radix-ui/react-tabs' import { useSetRecoilState } from 'recoil' import PhotoAlbum from 'react-photo-album' import { BarsArrowDownIcon, BarsArrowUpIcon } from '@heroicons/react/24/outline' @@ -50,6 +51,9 @@ enum SortBy { const SORT_BY_NAME = 'Name' const SORT_BY_CREATED_TIME = 'Created time' +const IMAGE_TAB = 'image' +const OUTPUT_TAB = 'output' + const SortByMap = { [SortBy.NAME]: SORT_BY_NAME, [SortBy.CTIME]: SORT_BY_CREATED_TIME, @@ -58,7 +62,7 @@ const SortByMap = { interface Props { show: boolean onClose: () => void - onPhotoClick(filename: string): void + onPhotoClick(tab: string, filename: string): void photoWidth: number } @@ -73,6 +77,7 @@ export default function FileManager(props: Props) { const ref = useRef(null) const [searchText, setSearchText] = useState('') const [debouncedSearchText, setDebouncedSearchText] = useState('') + const [tab, setTab] = useState(IMAGE_TAB) const [, cancel] = useDebounce( () => { @@ -102,14 +107,10 @@ export default function FileManager(props: Props) { [show, closeScrollTop] ) - const onClick = ({ index }: { index: number }) => { - onPhotoClick(filenames[index].name) - } - useEffect(() => { const fetchData = async () => { try { - const newFilenames = await getMedias() + const newFilenames = await getMedias(tab) setFileNames(newFilenames) } catch (e: any) { setToastState({ @@ -123,7 +124,7 @@ export default function FileManager(props: Props) { if (show) { fetchData() } - }, [show, setToastState]) + }, [show, setToastState, tab]) const onScroll = (event: SyntheticEvent) => { setScrollTop(event.currentTarget.scrollTop) @@ -141,19 +142,30 @@ export default function FileManager(props: Props) { const results: IndexSearchResult = await index.searchAsync( debouncedSearchText ) - return results.map((id: Id) => filenames[id as number]) - }, [filenames, debouncedSearchText]) + return _.orderBy( + results.map((id: Id) => filenames[id as number]), + sortBy, + sortOrder + ) + }, [filenames, debouncedSearchText, sortBy, sortOrder]) const photos: Photo[] = useMemo(() => { - return _.orderBy(filteredFilenames, sortBy, sortOrder).map( - (filename: Filename) => { - const width = photoWidth - const height = filename.height * (width / filename.width) - const src = `/media_thumbnail/${filename.name}?width=${width}&height=${height}` - return { src, height, width } - } - ) - }, [filteredFilenames, photoWidth, sortBy, sortOrder]) + if (!filteredFilenames) { + return [] + } + return filteredFilenames.map((filename: Filename) => { + const width = photoWidth + const height = filename.height * (width / filename.width) + const src = `/media_thumbnail/${tab}/${filename.name}?width=${width}&height=${height}` + return { src, height, width } + }) + }, [filteredFilenames, photoWidth, tab]) + + const onClick = ({ index }: { index: number }) => { + if (filteredFilenames) { + onPhotoClick(tab, filteredFilenames[index].name) + } + } return ( - - + setTab(val)} > - - ) => { - evt.preventDefault() - evt.stopPropagation() - const target = evt.target as HTMLInputElement - setSearchText(target.value) - }} - placeholder="Search by file name" - /> - + + + Image Directory + + + Output Directory + + + - { - if (val === SORT_BY_CREATED_TIME) { - setSortBy(SortBy.CTIME) - } else { - setSortBy(SortBy.NAME) + + + ) => { + evt.preventDefault() + evt.stopPropagation() + const target = evt.target as HTMLInputElement + setSearchText(target.value) + }} + placeholder="Search by file name" + /> + + + { + if (val === SORT_BY_CREATED_TIME) { + setSortBy(SortBy.CTIME) + } else { + setSortBy(SortBy.NAME) + } + }} + chevronDirection="down" + /> +