This commit is contained in:
Daniel Shleifman
2021-07-02 17:56:32 +03:00
parent bc717647ea
commit dbfc1db5d2
4 changed files with 533 additions and 459 deletions

View File

@@ -28,7 +28,7 @@ const Sidebar = ({ isDrawerOpen, setIsDonationDialogOpen, isOffline, isLoading }
<Divider /> <Divider />
<List> <List>
<SettingsDialog /> <SettingsDialog isOffline={isOffline} isLoading={isLoading} />
<AboutDialog /> <AboutDialog />

View File

@@ -18,7 +18,7 @@ import {
useMediaQuery, useMediaQuery,
useTheme, useTheme,
} from '@material-ui/core' } from '@material-ui/core'
import { settingsHost, setTorrServerHost, getTorrServerHost } from 'utils/Hosts' import { settingsHost } from 'utils/Hosts'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Header } from 'style/DialogStyles' import { Header } from 'style/DialogStyles'
@@ -26,94 +26,26 @@ import AppBar from '@material-ui/core/AppBar'
import Tabs from '@material-ui/core/Tabs' import Tabs from '@material-ui/core/Tabs'
import Tab from '@material-ui/core/Tab' import Tab from '@material-ui/core/Tab'
import SwipeableViews from 'react-swipeable-views' import SwipeableViews from 'react-swipeable-views'
import styled, { css } from 'styled-components'
import { USBIcon, RAMIcon } from 'icons' import { USBIcon, RAMIcon } from 'icons'
const FooterSection = styled.div` import {
padding: 20px; FooterSection,
display: flex; Divider,
align-items: center; PreloadCacheValue,
justify-content: space-between; MainSettingsContent,
background: #e8e5eb; SecondarySettingsContent,
StorageButton,
> :last-child > :not(:last-child) { StorageIconWrapper,
margin-right: 10px; CacheSizeSettings,
} CacheStorageSelector,
` CacheStorageSettings,
const Divider = styled.div` SettingSection,
height: 1px; SettingLabel,
background-color: rgba(0, 0, 0, 0.12); SettingSectionLabel,
margin: 30px 0; PreloadCachePercentage,
` cacheBeforeReaderColor,
cacheAfterReaderColor,
const PreloadCachePercentage = styled.div.attrs( } from './style'
({
value,
// theme: {
// dialogTorrentDetailsContent: { gradientEndColor },
// },
}) => {
const gradientStartColor = 'lightblue'
const gradientEndColor = 'orangered'
return {
// this block is here according to styled-components recomendation about fast changable components
style: {
background: `linear-gradient(to right, ${gradientEndColor} 0%, ${gradientEndColor} ${value}%, ${gradientStartColor} ${value}%, ${gradientStartColor} 100%)`,
},
}
},
)`
${({ label, isPreloadEnabled }) => css`
border: 1px solid;
padding: 10px 20px;
border-radius: 5px;
color: #000;
margin-bottom: 10px;
position: relative;
:before {
content: '${label}';
display: grid;
place-items: center;
font-size: 20px;
}
${isPreloadEnabled &&
css`
:after {
content: '';
width: 100%;
height: 3px;
background: green;
position: absolute;
bottom: 0;
left: 0;
}
`}
`}
`
const PreloadCacheValue = styled.div`
${({ color }) => css`
display: grid;
grid-template-columns: max-content 100px 1fr;
gap: 10px;
align-items: center;
:not(:last-child) {
margin-bottom: 5px;
}
:before {
content: '';
background: ${color};
width: 15px;
height: 15px;
border-radius: 50%;
}
`}
`
const a11yProps = index => ({ const a11yProps = index => ({
id: `full-width-tab-${index}`, id: `full-width-tab-${index}`,
@@ -126,103 +58,57 @@ const TabPanel = ({ children, value, index, ...other }) => (
</div> </div>
) )
const MainSettingsContent = styled.div` const defaultSettings = {
min-height: 500px; CacheSize: 96,
display: grid; ReaderReadAHead: 95,
grid-template-columns: repeat(2, 1fr); UseDisk: false,
gap: 40px; UploadRateLimit: 0,
padding: 20px; TorrentsSavePath: '',
ConnectionsLimit: 23,
@media (max-width: 930px) { DhtConnectionLimit: 500,
grid-template-columns: 1fr; DisableDHT: false,
} DisablePEX: false,
` DisableTCP: false,
const SecondarySettingsContent = styled.div` DisableUPNP: false,
min-height: 500px; DisableUTP: true,
padding: 20px; DisableUpload: false,
` DownloadRateLimit: 0,
EnableDebug: false,
const StorageButton = styled.div` EnableIPv6: false,
display: grid; ForceEncrypt: false,
place-items: center; PeersListenPort: 0,
gap: 10px; PreloadBuffer: false,
` RemoveCacheOnDrop: false,
RetrackersMode: 1,
const StorageIconWrapper = styled.div` Strategy: 0,
${({ selected }) => css` TorrentDisconnectTimeout: 30,
width: 150px; }
height: 150px;
border-radius: 50%;
background: ${selected ? 'blue' : 'lightgray'};
transition: 0.2s;
${!selected &&
css`
cursor: pointer;
:hover {
background: orangered;
}
`}
svg {
transform: rotate(-45deg) scale(0.75);
}
`}
`
const CacheSizeSettings = styled.div``
const CacheStorageSelector = styled.div`
display: grid;
grid-template-rows: max-content 1fr;
grid-template-columns: 1fr 1fr;
grid-template-areas: 'label label';
place-items: center;
@media (max-width: 930px) {
grid-template-columns: repeat(2, max-content);
column-gap: 30px;
}
`
const CacheStorageSettings = styled.div``
const SettingSection = styled.section``
const SettingLabel = styled.div``
const SettingSectionLabel = styled.div`
font-size: 25px;
padding-bottom: 20px;
`
export default function SettingsDialog({ handleClose }) { export default function SettingsDialog({ handleClose }) {
const { t } = useTranslation() const { t } = useTranslation()
const fullScreen = useMediaQuery('@media (max-width:930px)') const fullScreen = useMediaQuery('@media (max-width:930px)')
const [settings, setSets] = useState({}) const [settings, setSettings] = useState()
const [show, setShow] = useState(false) const [show, setShow] = useState(false)
const [tsHost, setTSHost] = useState(getTorrServerHost())
useEffect(() => { useEffect(() => {
axios axios
.post(settingsHost(), { action: 'get' }) .post(settingsHost(), { action: 'get' })
.then(({ data }) => { .then(({ data }) => {
setSets({ ...data, CacheSize: data.CacheSize / (1024 * 1024) }) setSettings({ ...data, CacheSize: data.CacheSize / (1024 * 1024) })
setShow(true) setShow(true)
}) })
.catch(() => setShow(false)) .catch(() => setShow(false))
}, [tsHost]) }, [])
const handleSave = () => { const handleSave = () => {
handleClose() handleClose()
const sets = JSON.parse(JSON.stringify(settings)) const sets = JSON.parse(JSON.stringify(settings))
sets.CacheSize *= 1024 * 1024 sets.CacheSize = cacheSize * 1024 * 1024
sets.ReaderReadAHead = cachePercentage
axios.post(settingsHost(), { action: 'set', sets }) axios.post(settingsHost(), { action: 'set', sets })
} }
const onInputHost = ({ target: { value } }) => {
const host = value.replace(/\/$/gi, '')
setTorrServerHost(host)
setTSHost(host)
}
const inputForm = ({ target: { type, value, checked, id } }) => { const inputForm = ({ target: { type, value, checked, id } }) => {
const sets = JSON.parse(JSON.stringify(settings)) const sets = JSON.parse(JSON.stringify(settings))
@@ -242,7 +128,7 @@ export default function SettingsDialog({ handleClose }) {
} else if (type === 'url') { } else if (type === 'url') {
sets[id] = value sets[id] = value
} }
setSets(sets) setSettings(sets)
} }
const { const {
@@ -267,7 +153,9 @@ export default function SettingsDialog({ handleClose }) {
UseDisk, UseDisk,
TorrentsSavePath, TorrentsSavePath,
RemoveCacheOnDrop, RemoveCacheOnDrop,
} = settings } = settings || {}
const updateSettings = newProps => setSettings({ ...settings, ...newProps })
const { direction } = useTheme() const { direction } = useTheme()
const [selectedTab, setSelectedTab] = useState(0) const [selectedTab, setSelectedTab] = useState(0)
@@ -276,14 +164,16 @@ export default function SettingsDialog({ handleClose }) {
const handleChangeIndex = index => setSelectedTab(index) const handleChangeIndex = index => setSelectedTab(index)
const [cacheSize, setCacheSize] = useState(96) const [cacheSize, setCacheSize] = useState(32)
const [cachePercentage, setCachePercentage] = useState(95) const [cachePercentage, setCachePercentage] = useState(40)
const [isProMode, setIsProMode] = useState(JSON.parse(localStorage.getItem('isProMode')) || false) const [isProMode, setIsProMode] = useState(JSON.parse(localStorage.getItem('isProMode')) || false)
const [isRamSelected, setIsRamSelected] = useState(true)
const handleSliderChange = (_, newValue) => { useEffect(() => {
setCacheSize(newValue) if (!CacheSize || !ReaderReadAHead) return
}
setCacheSize(CacheSize)
setCachePercentage(ReaderReadAHead)
}, [CacheSize, ReaderReadAHead])
const handleBlur = ({ target: { value } }) => { const handleBlur = ({ target: { value } }) => {
if (value < 32) return setCacheSize(32) if (value < 32) return setCacheSize(32)
@@ -300,6 +190,7 @@ export default function SettingsDialog({ handleClose }) {
<Dialog open onClose={handleClose} fullScreen={fullScreen} fullWidth maxWidth='md'> <Dialog open onClose={handleClose} fullScreen={fullScreen} fullWidth maxWidth='md'>
<Header>{t('Settings')}</Header> <Header>{t('Settings')}</Header>
{settings ? (
<> <>
<AppBar position='static' color='default'> <AppBar position='static' color='default'>
<Tabs <Tabs
@@ -335,14 +226,14 @@ export default function SettingsDialog({ handleClose }) {
isPreloadEnabled={PreloadBuffer} isPreloadEnabled={PreloadBuffer}
/> />
<PreloadCacheValue color='orangered'> <PreloadCacheValue color={cacheBeforeReaderColor}>
<div> <div>
{100 - cachePercentage}% ({Math.round((cacheSize / 100) * (100 - cachePercentage))} МБ) {100 - cachePercentage}% ({Math.round((cacheSize / 100) * (100 - cachePercentage))} МБ)
</div> </div>
<div>От кеша будет оставаться позади воспроизводимого блока</div> <div>От кеша будет оставаться позади воспроизводимого блока</div>
</PreloadCacheValue> </PreloadCacheValue>
<PreloadCacheValue color='lightblue'> <PreloadCacheValue color={cacheAfterReaderColor}>
<div> <div>
{cachePercentage}% ({Math.round((cacheSize / 100) * cachePercentage)} МБ) {cachePercentage}% ({Math.round((cacheSize / 100) * cachePercentage)} МБ)
</div> </div>
@@ -356,7 +247,13 @@ export default function SettingsDialog({ handleClose }) {
<Grid container spacing={2} alignItems='center'> <Grid container spacing={2} alignItems='center'>
<Grid item xs> <Grid item xs>
<Slider min={32} max={1024} value={cacheSize} onChange={handleSliderChange} step={8} /> <Slider
min={32}
max={1024}
value={cacheSize}
onChange={(_, newValue) => setCacheSize(newValue)}
step={8}
/>
</Grid> </Grid>
{isProMode && ( {isProMode && (
@@ -367,12 +264,7 @@ export default function SettingsDialog({ handleClose }) {
onChange={handleInputChange} onChange={handleInputChange}
onBlur={handleBlur} onBlur={handleBlur}
style={{ width: '65px' }} style={{ width: '65px' }}
inputProps={{ inputProps={{ step: 8, min: 32, max: 20000, type: 'number' }}
step: 8,
min: 32,
max: 20000,
type: 'number',
}}
/> />
</Grid> </Grid>
)} )}
@@ -403,72 +295,56 @@ export default function SettingsDialog({ handleClose }) {
if (value > 100) return setCachePercentage(100) if (value > 100) return setCachePercentage(100)
}} }}
style={{ width: '65px' }} style={{ width: '65px' }}
inputProps={{ inputProps={{ min: 0, max: 100, type: 'number' }}
min: 0,
max: 100,
type: 'number',
}}
/> />
</Grid> </Grid>
)} )}
</Grid> </Grid>
</SettingSection> </SettingSection>
<SettingSection>
<FormControlLabel <FormControlLabel
control={<Switch checked={PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='primary' />} control={
<Switch checked={!!PreloadBuffer} onChange={inputForm} id='PreloadBuffer' color='primary' />
}
label={t('PreloadBuffer')} label={t('PreloadBuffer')}
/> />
</SettingSection>
</CacheSizeSettings> </CacheSizeSettings>
{isRamSelected ? ( {UseDisk ? (
<CacheStorageSelector>
<SettingSectionLabel style={{ placeSelf: 'start', gridArea: 'label' }}>
Место хранения кеша
</SettingSectionLabel>
<StorageButton>
<StorageIconWrapper selected>
<RAMIcon />
</StorageIconWrapper>
<div>Оперативная память</div>
</StorageButton>
<StorageButton>
<StorageIconWrapper onClick={() => setIsRamSelected(false)}>
<USBIcon />
</StorageIconWrapper>
<div>Диск</div>
</StorageButton>
</CacheStorageSelector>
) : (
<CacheStorageSettings> <CacheStorageSettings>
<SettingSectionLabel>Место хранения кеша</SettingSectionLabel> <SettingSectionLabel>Место хранения кеша</SettingSectionLabel>
<ButtonGroup fullWidth color='primary'> <div style={{ display: 'grid', gridAutoFlow: 'column' }}>
<Button onClick={() => setIsRamSelected(true)}> <StorageButton small onClick={() => updateSettings({ UseDisk: false })}>
<div> <StorageIconWrapper small>
<RAMIcon width='50px' /> <RAMIcon color='#323637' />
<div>Оперативная память</div> </StorageIconWrapper>
</div>
</Button> <div>Оперативная память</div>
</StorageButton>
<StorageButton small selected>
<StorageIconWrapper small selected>
<USBIcon color='#dee3e5' />
</StorageIconWrapper>
<Button variant='contained'>
<div>
<USBIcon width='50px' color='white' />
<div>Диск</div> <div>Диск</div>
</StorageButton>
</div> </div>
</Button>
</ButtonGroup>
<FormControlLabel <FormControlLabel
control={ control={
<Switch checked={RemoveCacheOnDrop} onChange={inputForm} id='RemoveCacheOnDrop' color='primary' /> <Switch
checked={RemoveCacheOnDrop}
onChange={inputForm}
id='RemoveCacheOnDrop'
color='primary'
/>
} }
label={t('RemoveCacheOnDrop')} label={t('RemoveCacheOnDrop')}
/> />
<small>{t('RemoveCacheOnDropDesc')}</small> <small>{t('RemoveCacheOnDropDesc')}</small>
<TextField <TextField
onChange={inputForm} onChange={inputForm}
margin='dense' margin='dense'
@@ -479,6 +355,28 @@ export default function SettingsDialog({ handleClose }) {
fullWidth fullWidth
/> />
</CacheStorageSettings> </CacheStorageSettings>
) : (
<CacheStorageSelector>
<SettingSectionLabel style={{ placeSelf: 'start', gridArea: 'label' }}>
Место хранения кеша
</SettingSectionLabel>
<StorageButton selected>
<StorageIconWrapper selected>
<RAMIcon color='#dee3e5' />
</StorageIconWrapper>
<div>Оперативная память</div>
</StorageButton>
<StorageButton onClick={() => updateSettings({ UseDisk: true })}>
<StorageIconWrapper>
<USBIcon color='#323637' />
</StorageIconWrapper>
<div>Диск</div>
</StorageButton>
</CacheStorageSelector>
)} )}
</MainSettingsContent> </MainSettingsContent>
</TabPanel> </TabPanel>
@@ -599,6 +497,9 @@ export default function SettingsDialog({ handleClose }) {
</TabPanel> </TabPanel>
</SwipeableViews> </SwipeableViews>
</> </>
) : (
'loading...'
)}
{/* <DialogTitle id='form-dialog-title'>{t('Settings')}</DialogTitle> {/* <DialogTitle id='form-dialog-title'>{t('Settings')}</DialogTitle>
<DialogContent> <DialogContent>
<TextField <TextField
@@ -805,6 +706,18 @@ export default function SettingsDialog({ handleClose }) {
{t('Cancel')} {t('Cancel')}
</Button> </Button>
<Button
onClick={() => {
setCacheSize(defaultSettings.CacheSize)
setCachePercentage(defaultSettings.ReaderReadAHead)
updateSettings(defaultSettings)
}}
color='secondary'
variant='outlined'
>
Reset to default
</Button>
<Button variant='contained' onClick={handleSave} color='primary'> <Button variant='contained' onClick={handleSave} color='primary'>
{t('Save')} {t('Save')}
</Button> </Button>

View File

@@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
import SettingsDialog from './SettingsDialog' import SettingsDialog from './SettingsDialog'
export default function SettingsDialogButton() { export default function SettingsDialogButton({ isOffline, isLoading }) {
const { t } = useTranslation() const { t } = useTranslation()
const [isDialogOpen, setIsDialogOpen] = useState(false) const [isDialogOpen, setIsDialogOpen] = useState(false)
@@ -16,7 +16,7 @@ export default function SettingsDialogButton() {
return ( return (
<div> <div>
<ListItem button onClick={handleClickOpen}> <ListItem disabled={isOffline || isLoading} button onClick={handleClickOpen}>
<ListItemIcon> <ListItemIcon>
<SettingsIcon /> <SettingsIcon />
</ListItemIcon> </ListItemIcon>

View File

@@ -0,0 +1,161 @@
import styled, { css } from 'styled-components'
import { mainColors } from 'style/colors'
export const cacheBeforeReaderColor = '#b3dfc9'
export const cacheAfterReaderColor = mainColors.light.primary
export const FooterSection = styled.div`
padding: 20px;
display: flex;
align-items: center;
justify-content: space-between;
background: #e8e5eb;
> :last-child > :not(:last-child) {
margin-right: 10px;
}
`
export const Divider = styled.div`
height: 1px;
background-color: rgba(0, 0, 0, 0.12);
margin: 30px 0;
`
export const PreloadCacheValue = styled.div`
${({ color }) => css`
display: grid;
grid-template-columns: max-content 100px 1fr;
gap: 10px;
align-items: center;
:not(:last-child) {
margin-bottom: 5px;
}
:before {
content: '';
background: ${color};
width: 15px;
height: 15px;
border-radius: 50%;
}
`}
`
export const MainSettingsContent = styled.div`
min-height: 500px;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 40px;
padding: 20px;
@media (max-width: 930px) {
grid-template-columns: 1fr;
}
`
export const SecondarySettingsContent = styled.div`
min-height: 500px;
padding: 20px;
`
export const StorageButton = styled.div`
${({ small, selected }) => css`
transition: 0.2s;
cursor: default;
${!selected &&
css`
cursor: pointer;
:hover {
filter: brightness(0.8);
}
`}
${small
? css`
display: grid;
grid-template-columns: max-content 1fr;
gap: 20px;
align-items: center;
margin-bottom: 20px;
`
: css`
display: grid;
place-items: center;
gap: 10px;
`}
`}
`
export const StorageIconWrapper = styled.div`
${({ selected, small }) => css`
width: ${small ? '60px' : '150px'};
height: ${small ? '60px' : '150px'};
border-radius: 50%;
background: ${selected ? '#323637' : '#dee3e5'};
svg {
transform: rotate(-45deg) scale(0.75);
}
`}
`
export const CacheSizeSettings = styled.div``
export const CacheStorageSelector = styled.div`
display: grid;
grid-template-rows: max-content 1fr;
grid-template-columns: 1fr 1fr;
grid-template-areas: 'label label';
place-items: center;
@media (max-width: 930px) {
grid-template-columns: repeat(2, max-content);
column-gap: 30px;
}
`
export const CacheStorageSettings = styled.div``
export const SettingSection = styled.section``
export const SettingLabel = styled.div``
export const SettingSectionLabel = styled.div`
font-size: 25px;
padding-bottom: 20px;
`
export const PreloadCachePercentage = styled.div.attrs(({ value }) => ({
// this block is here according to styled-components recomendation about fast changable components
style: {
background: `linear-gradient(to right, ${cacheBeforeReaderColor} 0%, ${cacheBeforeReaderColor} ${value}%, ${cacheAfterReaderColor} ${value}%, ${cacheAfterReaderColor} 100%)`,
},
}))`
${({ label, isPreloadEnabled }) => css`
border: 1px solid #323637;
padding: 10px 20px;
border-radius: 5px;
color: #000;
margin-bottom: 10px;
position: relative;
:before {
content: '${label}';
display: grid;
place-items: center;
font-size: 20px;
}
${isPreloadEnabled &&
css`
:after {
content: '';
width: 100%;
height: 2px;
background: #323637;
position: absolute;
bottom: 0;
left: 0;
}
`}
`}
`