refactor: batch 1

This commit is contained in:
鲁树人
2025-05-17 05:59:39 +09:00
parent 089d66cbf4
commit 13c669b4ea
23 changed files with 828 additions and 533 deletions

View File

@@ -1,5 +1,3 @@
import { VStack } from '@chakra-ui/react';
import { selectFiles } from './fileListingSlice';
import { useAppSelector } from '~/hooks';
import { FileRow } from './FileRow';
@@ -8,10 +6,10 @@ export function FileListing() {
const files = useAppSelector(selectFiles);
return (
<VStack>
<div className="flex flex-row flex-wrap gap-8">
{Object.entries(files).map(([id, file]) => (
<FileRow key={id} id={id} file={file} />
))}
</VStack>
</div>
);
}

View File

@@ -1,24 +1,9 @@
import { useRef } from 'react';
import {
Box,
Button,
Card,
CardBody,
Collapse,
GridItem,
Link,
VStack,
Wrap,
WrapItem,
useDisclosure,
} from '@chakra-ui/react';
import { FileRowResponsiveGrid } from './FileRowResponsiveGrid';
import { DecryptedAudioFile, deleteFile, ProcessState } from './fileListingSlice';
import { useAppDispatch } from '~/hooks';
import { AnimationDefinition } from 'framer-motion';
import { AlbumImage } from './AlbumImage';
import { SongMetadata } from './SongMetadata';
import { FileError } from './FileError';
import classNames from 'classnames';
interface FileRowProps {
id: string;
@@ -26,7 +11,7 @@ interface FileRowProps {
}
export function FileRow({ id, file }: FileRowProps) {
const { isOpen, onClose } = useDisclosure({ defaultIsOpen: true });
// const { isOpen, onClose } = useDisclosure({ defaultIsOpen: true });
const dispatch = useAppDispatch();
const isDecrypted = file.state === ProcessState.COMPLETE;
const metadata = file.metadata;
@@ -35,81 +20,54 @@ export function FileRow({ id, file }: FileRowProps) {
const decryptedName = nameWithoutExt + '.' + file.ext;
const audioPlayerRef = useRef<HTMLAudioElement>(null);
const togglePlay = () => {
const player = audioPlayerRef.current;
if (!player) {
return;
}
if (player.paused) {
player.play();
} else {
player.pause();
}
};
const onCollapseAnimationComplete = (definition: AnimationDefinition) => {
const _onCollapseAnimationComplete = (definition: AnimationDefinition) => {
if (definition === 'exit') {
dispatch(deleteFile({ id }));
}
};
return (
<Collapse
in={isOpen}
animateOpacity
unmountOnExit
startingHeight={0}
onAnimationComplete={onCollapseAnimationComplete}
style={{ width: '100%', padding: '0.25rem' }}
>
<Card w="full" data-testid="file-row">
<CardBody>
<FileRowResponsiveGrid>
<GridItem area="cover">
<AlbumImage name={metadata?.album} url={metadata?.cover} />
</GridItem>
<GridItem area="title">
<Box w="full" as="h4" fontWeight="semibold" mt="1" textAlign={{ base: 'center', md: 'left' }}>
<span data-testid="audio-meta-song-name">{metadata?.name ?? nameWithoutExt}</span>
</Box>
</GridItem>
<GridItem area="meta">
{isDecrypted && metadata && <SongMetadata metadata={metadata} />}
{file.state === ProcessState.ERROR && <FileError error={file.errorMessage} code={file.errorCode} />}
</GridItem>
<GridItem area="action" alignSelf="center">
<VStack>
{file.decrypted && <audio controls autoPlay={false} src={file.decrypted} ref={audioPlayerRef} />}
<div className="card bg-base-100 shadow-sm w-full md:w-[30%] " data-testid="file-row">
<div className="card-body items-center text-center px-2">
<h2
className="card-title overflow-hidden text-ellipsis block max-w-full whitespace-nowrap"
data-testid="audio-meta-song-name"
>
{metadata?.name ?? nameWithoutExt}
</h2>
<Wrap>
{isDecrypted && (
<>
<WrapItem>
<Button type="button" onClick={togglePlay}>
/
</Button>
</WrapItem>
<WrapItem>
{file.decrypted && (
<Link href={file.decrypted} download={decryptedName}>
<Button as="span"></Button>
</Link>
)}
</WrapItem>
</>
)}
<WrapItem>
<Button type="button" onClick={onClose}>
</Button>
</WrapItem>
</Wrap>
</VStack>
</GridItem>
</FileRowResponsiveGrid>
</CardBody>
</Card>
</Collapse>
<div>
{file.state === ProcessState.ERROR && <FileError error={file.errorMessage} code={file.errorCode} />}
{isDecrypted && (
<audio
className="max-w-[100%]"
aria-disabled={!file.decrypted}
controls
autoPlay={false}
src={file.decrypted}
ref={audioPlayerRef}
/>
)}
</div>
<div className="card-actions justify-end">
<a
href={file.decrypted}
download={decryptedName}
title={`下载: ${decryptedName}`}
className={classNames('btn', {
'btn-primary': file.decrypted,
'cursor-not-allowed pointer-events-none': !file.decrypted,
})}
data-testid="audio-download"
>
</a>
<button type="button" className="btn btn-error" onClick={() => dispatch(deleteFile({ id }))}>
</button>
</div>
</div>
</div>
);
}