Improved filebrowser (#52)

* file archive refactor, list dir perf optimization

* code refactoring
This commit is contained in:
Marco
2023-05-26 11:10:10 +02:00
committed by GitHub
parent 8cf130ec23
commit 5b70d25bef
7 changed files with 120 additions and 96 deletions

View File

@@ -17,13 +17,15 @@ import {
Paper,
SpeedDial,
SpeedDialAction,
SpeedDialIcon
SpeedDialIcon,
Typography
} from '@mui/material'
import DeleteForeverIcon from '@mui/icons-material/DeleteForever'
import VideoFileIcon from '@mui/icons-material/VideoFile'
import FolderIcon from '@mui/icons-material/Folder'
import { Buffer } from 'buffer'
import { useEffect, useMemo, useState } from 'react'
import { useEffect, useMemo, useState, useTransition } from 'react'
import { useSelector } from 'react-redux'
import { BehaviorSubject, Subject, combineLatestWith, map, share } from 'rxjs'
import { useObservable } from './hooks/observable'
@@ -41,10 +43,41 @@ export default function Downloaded() {
const files$ = useMemo(() => new Subject<DirectoryEntry[]>(), [])
const selected$ = useMemo(() => new BehaviorSubject<string[]>([]), [])
const fetcher = () => fetch(`${serverAddr}/downloaded`)
const [isPending, startTransition] = useTransition()
const fetcher = () => fetch(`${serverAddr}/downloaded`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ subdir: '' })
})
.then(res => res.json())
.then(data => files$.next(data))
const fetcherSubfolder = (sub: string) => {
const folders = sub.split('/')
let subdir = folders.length > 2
? folders.slice(-2).join('/')
: folders.pop()
fetch(`${serverAddr}/downloaded`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ subdir: subdir })
})
.then(res => res.json())
.then(data => {
files$.next([{
isDirectory: true,
name: '..',
path: '',
}, ...data])
})
}
const selectable$ = useMemo(() => files$.pipe(
combineLatestWith(selected$),
map(([data, selected]) => data.map(x => ({
@@ -82,11 +115,20 @@ export default function Downloaded() {
fetcher()
}, [settings.serverAddr, settings.serverPort])
const onFileClick = (path: string) => startTransition(() => {
window.open(`${serverAddr}/play?path=${Buffer.from(path).toString('hex')}`)
})
const onFolderClick = (path: string) => startTransition(() => {
fetcherSubfolder(path)
})
return (
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Backdrop
sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={!(files$.observed)}
open={!(files$.observed) || isPending}
>
<CircularProgress color="primary" />
</Backdrop>
@@ -95,13 +137,16 @@ export default function Downloaded() {
display: 'flex',
flexDirection: 'column',
}}>
<Typography pb={0} variant="h5" color="primary">
{'Archive'}
</Typography>
<List sx={{ width: '100%', bgcolor: 'background.paper' }}>
{selectable.length === 0 && 'No files found'}
{selectable.map((file) => (
<ListItem
key={file.shaSum}
secondaryAction={
<Checkbox
!file.isDirectory && <Checkbox
edge="end"
checked={file.selected}
onChange={() => addSelected(file.name)}
@@ -109,13 +154,18 @@ export default function Downloaded() {
}
disablePadding
>
<ListItemButton>
<ListItemButton onClick={
() => file.isDirectory
? onFolderClick(file.path)
: onFileClick(file.path)
}>
<ListItemIcon>
<VideoFileIcon />
{file.isDirectory
? <FolderIcon />
: <VideoFileIcon />
}
</ListItemIcon>
<ListItemText primary={file.name} onClick={() => window.open(
`${serverAddr}/play?path=${Buffer.from(file.path).toString('hex')}`
)} />
<ListItemText primary={file.name} />
</ListItemButton>
</ListItem>
))}
@@ -159,7 +209,8 @@ export default function Downloaded() {
<Button onClick={() => {
deleteSelected()
setOpenDialog(false)
}} autoFocus>
}} autoFocus
>
Ok
</Button>
</DialogActions>

View File

@@ -19,7 +19,13 @@ import {
} from '@mui/material'
import { useEffect, useMemo, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { Subject, debounceTime, distinctUntilChanged, map, takeWhile } from 'rxjs'
import {
Subject,
debounceTime,
distinctUntilChanged,
map,
takeWhile
} from 'rxjs'
import { CliArguments } from './features/core/argsParser'
import I18nBuilder from './features/core/intl'
import { RPCClient } from './features/core/rpcClient'
@@ -122,7 +128,7 @@ export default function Settings() {
minHeight: 240,
}}
>
<Typography pb={2} variant="h6" color="primary">
<Typography pb={3} variant="h5" color="primary">
{i18n.t('settingsAnchor')}
</Typography>
<FormGroup>

View File

@@ -66,9 +66,10 @@ export type DirectoryEntry = {
name: string
path: string
shaSum: string
isDirectory: boolean
}
export type DeleteRequest = Omit<DirectoryEntry, 'name'>
export type DeleteRequest = Omit<DirectoryEntry, 'name' | 'isDirectory'>
export type PlayRequest = Omit<DirectoryEntry, 'shaSum' | 'name'>
export type PlayRequest = Omit<DirectoryEntry, 'shaSum' | 'name' | 'isDirectory'>