aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/downloadManager/DownloadManagerDashboard.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/downloadManager/DownloadManagerDashboard.tsx')
-rw-r--r--src/components/downloadManager/DownloadManagerDashboard.tsx288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/components/downloadManager/DownloadManagerDashboard.tsx b/src/components/downloadManager/DownloadManagerDashboard.tsx
new file mode 100644
index 000000000..86facc476
--- /dev/null
+++ b/src/components/downloadManager/DownloadManagerDashboard.tsx
@@ -0,0 +1,288 @@
1import { Component } from 'react';
2import { observer } from 'mobx-react';
3import { IntlShape, defineMessages, injectIntl } from 'react-intl';
4import { shell } from 'electron';
5import prettyBytes from 'pretty-bytes';
6import {
7 Typography,
8 Card,
9 CardContent,
10 LinearProgress,
11 Box,
12 IconButton,
13 ListItemButton,
14 ListItemIcon,
15 ListItemText,
16} from '@mui/material';
17import { mdiDownload } from '@mdi/js';
18import PlayArrowIcon from '@mui/icons-material/PlayArrow';
19import PauseIcon from '@mui/icons-material/Pause';
20import CancelIcon from '@mui/icons-material/Cancel';
21import FolderIcon from '@mui/icons-material/Folder';
22import DeleteIcon from '@mui/icons-material/Delete';
23import ClearAllIcon from '@mui/icons-material/ClearAll';
24import { round } from 'lodash';
25import { RealStores } from '../../stores';
26import { Actions } from '../../actions/lib/actions';
27import Icon from '../ui/icon';
28
29const messages = defineMessages({
30 headline: {
31 id: 'downloadManager.headline',
32 defaultMessage: 'Download Manager',
33 },
34 empty: {
35 id: 'downloadManager.empty',
36 defaultMessage: 'Your download list is empty.',
37 },
38});
39
40interface IProps {
41 intl: IntlShape;
42 stores?: RealStores;
43 actions?: Actions;
44}
45
46interface IState {
47 data: string;
48}
49
50// eslint-disable-next-line react/prefer-stateless-function
51class DownloadManagerDashboard extends Component<IProps, IState> {
52 render() {
53 const { intl, stores, actions } = this.props;
54
55 const downloads = stores?.app.downloads ?? [];
56
57 return (
58 <div className="settings__main">
59 <div className="settings__header">
60 <span className="settings__header-item">
61 <Box
62 sx={{
63 display: 'flex',
64 justifyContent: 'center',
65 alignItems: 'center',
66 }}
67 gap={1.5}
68 >
69 <Icon icon={mdiDownload} size={1.5} />
70 {intl.formatMessage(messages.headline)}
71 <span className="badge badge--success">beta</span>
72 </Box>
73 </span>
74 </div>
75 <div className="settings__body">
76 {downloads.length === 0 ? (
77 <Box
78 sx={{
79 display: 'flex',
80 flexDirection: 'column',
81 justifyContent: 'center',
82 alignItems: 'center',
83 }}
84 gap={4}
85 >
86 <Icon icon={mdiDownload} size={1.8} />
87 <Typography variant="h4">
88 {intl.formatMessage(messages.empty)}
89 </Typography>
90 </Box>
91 ) : (
92 <Box
93 sx={{
94 display: 'flex',
95 flexDirection: 'row',
96 justifyContent: 'flex-end',
97 height: 'fit-content',
98 }}
99 >
100 <Box
101 sx={{
102 maxWidth: '176px',
103 }}
104 >
105 <ListItemButton
106 onClick={() => {
107 actions?.app.removeDownload(null);
108 }}
109 >
110 <ListItemIcon>
111 <ClearAllIcon />
112 </ListItemIcon>
113 <ListItemText primary="Clear all completed" />
114 </ListItemButton>
115 </Box>
116 </Box>
117 )}
118 {downloads.map(download => {
119 const {
120 totalBytes,
121 receivedBytes,
122 filename,
123 url,
124 savePath,
125 state,
126 id,
127 paused,
128 } = download;
129
130 const downloadPercentage =
131 receivedBytes !== undefined && totalBytes !== undefined
132 ? round((receivedBytes / totalBytes) * 100, 2)
133 : null;
134
135 const stateParse =
136 state === 'progressing'
137 ? paused === false || paused === undefined
138 ? null
139 : 'Paused'
140 : state === 'cancelled'
141 ? 'Cancelled'
142 : state === 'completed'
143 ? null
144 : 'Error';
145
146 return (
147 <Card
148 key={id}
149 style={{
150 marginBottom: '16px',
151 height: 'fit-content',
152 display: 'flex',
153 }}
154 >
155 <Box
156 sx={{ display: 'flex', flexDirection: 'column', flexGrow: 1 }}
157 >
158 <CardContent>
159 <Box
160 sx={{
161 display: 'flex',
162 }}
163 gap={2}
164 >
165 <button
166 type="button"
167 disabled={state !== 'completed'}
168 style={{
169 pointerEvents:
170 state === 'completed' ? undefined : 'none',
171 }}
172 onClick={() => {
173 if (savePath) shell.openPath(savePath);
174 }}
175 >
176 <Typography
177 variant="h6"
178 color={state === 'completed' ? 'primary' : undefined}
179 sx={{
180 textDecoration:
181 stateParse !== null && stateParse !== 'Paused'
182 ? 'line-through'
183 : state === 'completed'
184 ? 'underline'
185 : null,
186 }}
187 >
188 {filename}
189 </Typography>
190 </button>
191 <Typography
192 variant="h6"
193 color={stateParse === 'Paused' ? '#ed6c02' : undefined}
194 >
195 {stateParse !== null && stateParse !== 'Paused'
196 ? stateParse
197 : stateParse === 'Paused'
198 ? stateParse
199 : null}
200 </Typography>
201 </Box>
202 <Typography variant="body2">{url}</Typography>
203 <LinearProgress
204 variant="determinate"
205 value={downloadPercentage || 0}
206 style={{ marginTop: '8px', marginBottom: '8px' }}
207 />
208 <Typography variant="body2">
209 {`${
210 downloadPercentage ? `${downloadPercentage}% - ` : ''
211 }${
212 receivedBytes ? `${prettyBytes(receivedBytes)} of ` : ''
213 }${totalBytes ? prettyBytes(totalBytes) : ''}`}
214 </Typography>
215 </CardContent>
216 </Box>
217
218 <Box
219 sx={{
220 display: 'flex',
221 flexDirection: 'column',
222 justifyContent: 'center',
223 alignItems: 'center',
224 padding: '8px',
225 }}
226 >
227 {state !== 'completed' && state !== 'cancelled' && (
228 <IconButton
229 color="error"
230 size="small"
231 onClick={() => {
232 actions?.app.stopDownload(id);
233 }}
234 >
235 <CancelIcon />
236 </IconButton>
237 )}
238 {state === 'progressing' && (
239 <IconButton
240 color={
241 paused === false || paused === undefined
242 ? 'warning'
243 : 'success'
244 }
245 size="small"
246 onClick={() => {
247 actions?.app.togglePauseDownload(id);
248 }}
249 >
250 {(paused === false || paused === undefined) && (
251 <PauseIcon />
252 )}
253 {paused && <PlayArrowIcon />}
254 </IconButton>
255 )}
256 {(state === 'cancelled' || state === 'completed') && (
257 <IconButton
258 color="error"
259 onClick={() => {
260 actions?.app.removeDownload(id);
261 }}
262 size="small"
263 >
264 <DeleteIcon />
265 </IconButton>
266 )}
267 {state !== 'cancelled' && (
268 <IconButton
269 color="primary"
270 onClick={() => {
271 if (savePath) shell.showItemInFolder(savePath);
272 }}
273 size="small"
274 >
275 <FolderIcon />
276 </IconButton>
277 )}
278 </Box>
279 </Card>
280 );
281 })}
282 </div>
283 </div>
284 );
285 }
286}
287
288export default injectIntl(observer(DownloadManagerDashboard));