diff --git a/src/decrypt-worker/constants.ts b/src/decrypt-worker/constants.ts index e5caa2f..2751e71 100644 --- a/src/decrypt-worker/constants.ts +++ b/src/decrypt-worker/constants.ts @@ -4,4 +4,5 @@ export enum DECRYPTION_WORKER_ACTION_NAME { export interface DecryptionResult { decrypted: string; // blob uri + ext: string; } diff --git a/src/features/file-listing/FileListing.tsx b/src/features/file-listing/FileListing.tsx index ef8fb74..5211cbf 100644 --- a/src/features/file-listing/FileListing.tsx +++ b/src/features/file-listing/FileListing.tsx @@ -1,72 +1,17 @@ -import { - Avatar, - Box, - Link, - Table, - TableContainer, - Tbody, - Td, - Text, - Th, - Thead, - Tr, - Wrap, - WrapItem, -} from '@chakra-ui/react'; +import { VStack } from '@chakra-ui/react'; -import { ProcessState, selectFiles } from './fileListingSlice'; +import { selectFiles } from './fileListingSlice'; import { useAppSelector } from '../../hooks'; +import { FileRow } from './FileRow'; export function FileListing() { const files = useAppSelector(selectFiles); return ( - - - - - - - - - - - {Object.entries(files).map(([id, file]) => ( - - - - - - ))} - -
封面元信息操作
- {file.metadata.cover && } - {!file.metadata.cover && 暂无封面} - - - {file.metadata.name || file.fileName} - - {file.state === ProcessState.COMPLETE && ( - <> - 专辑: {file.metadata.album} - 艺术家: {file.metadata.artist} - 专辑艺术家: {file.metadata.albumArtist} - - )} - - - 播放 - - {/* TODO: Use correct file name */} - {file.decrypted && ( - - 下载 - - )} - - 删除 - -
-
+ + {Object.entries(files).map(([id, file]) => ( + + ))} + ); } diff --git a/src/features/file-listing/FileRow.tsx b/src/features/file-listing/FileRow.tsx new file mode 100644 index 0000000..163c6f8 --- /dev/null +++ b/src/features/file-listing/FileRow.tsx @@ -0,0 +1,107 @@ +import { + Avatar, + Box, + Button, + Card, + CardBody, + Center, + Grid, + GridItem, + Link, + Text, + VStack, + Wrap, + WrapItem, +} from '@chakra-ui/react'; +import { DecryptedAudioFile, ProcessState } from './fileListingSlice'; +import { useRef } from 'react'; + +interface FileRowProps { + id: string; + file: DecryptedAudioFile; +} + +export function FileRow({ id, file }: FileRowProps) { + const isDecrypted = file.state === ProcessState.COMPLETE; + + const decryptedName = file.fileName.replace(/\.[a-z\d]{3,6}$/, '') + '.' + file.ext; + + const audioPlayerRef = useRef(null); + const togglePlay = () => { + const player = audioPlayerRef.current; + if (!player) { + return; + } + + if (player.paused) { + player.play(); + } else { + player.pause(); + } + }; + + return ( + + + + +
+ {file.metadata.cover && } + {!file.metadata.cover && 暂无封面} +
+
+ + + {file.metadata.name || file.fileName} + + + + {isDecrypted && ( + + 专辑: {file.metadata.album} + 艺术家: {file.metadata.artist} + 专辑艺术家: {file.metadata.albumArtist} + + )} + + + + {file.decrypted && + +
+
+
+ ); +} diff --git a/src/features/file-listing/fileListingSlice.ts b/src/features/file-listing/fileListingSlice.ts index fd44715..038c23d 100644 --- a/src/features/file-listing/fileListingSlice.ts +++ b/src/features/file-listing/fileListingSlice.ts @@ -27,6 +27,7 @@ export interface AudioMetadata { export interface DecryptedAudioFile { fileName: string; raw: string; // blob uri + ext: string; decrypted: string; // blob uri state: ProcessState; errorMessage: null | string; @@ -65,6 +66,7 @@ export const fileListingSlice = createSlice({ fileName: payload.fileName, raw: payload.blobURI, decrypted: '', + ext: '', state: ProcessState.UNTOUCHED, errorMessage: null, metadata: { @@ -91,6 +93,7 @@ export const fileListingSlice = createSlice({ file.state = ProcessState.COMPLETE; file.decrypted = action.payload.decrypted; + file.ext = action.payload.ext; // TODO: populate file metadata });