| 1 | import { createElement as h, Fragment } from 'react' |
| 2 | import { DirList, state, useSnapState } from './state' |
| 3 | import { Btn } from './components' |
| 4 | import { alertDialog, toast } from './dialog' |
| 5 | import { navigate } from './App' |
| 6 | import { apiCall } from '@hfs/shared/api' |
| 7 | import { reloadList, usePath } from './useFetchList' |
| 8 | import _ from 'lodash' |
| 9 | import { HTTP_MESSAGES, xlate, dirname, hfsEvent } from './misc' |
| 10 | import i18n from './i18n' |
| 11 | const { t, useI18N } = i18n |
| 12 | |
| 13 | export function ClipBar() { |
| 14 | const { clip, props } = useSnapState() |
| 15 | const { t } = useI18N() |
| 16 | const here = usePath() |
| 17 | if (!clip.length) |
| 18 | return null |
| 19 | const there = dirname(clip[0].uri) + '/' |
| 20 | return h('div', { id: 'clipBar' }, |
| 21 | h(Btn, { label: t('clipboard', { content: t('n_items', { n: clip.length }, "{n,plural, one{# item} other{# items}}"), }, `Clipboard ({content})`), |
| 22 | onClick: show, style: { flex: 1 } }), |
| 23 | h(Btn, { label: t`Paste`, icon: 'paste', onClick: paste, disabled: here === there || !props?.can_upload }), |
| 24 | h(Btn, { label: t`Cancel clipboard`, icon: 'close', onClick: emptyIt }), |
| 25 | h(Btn, { label: t('to_clipboard_source', "Back to source folder"), icon: 'parent', onClick: goBack, disabled: here === there, |
| 26 | tooltip: t('to_clipboard_source_tooltip', "Go to the folder where the clipboard contents are located"), |
| 27 | }), |
| 28 | ) |
| 29 | |
| 30 | function emptyIt() { |
| 31 | cut([]) |
| 32 | } |
| 33 | |
| 34 | function goBack() { |
| 35 | navigate(there) |
| 36 | } |
| 37 | |
| 38 | function show() { |
| 39 | alertDialog(h('div', { id: 'clipboard-content' }, |
| 40 | t('clipboard_list', "Items in clipboard:"), |
| 41 | clip.map(x => h('li', {}, x.name)), |
| 42 | )) |
| 43 | } |
| 44 | |
| 45 | async function paste() { |
| 46 | if (hfsEvent('paste', { from: state.clip, to: here }).isDefaultPrevented()) return |
| 47 | if (await moveFiles(clip.map(x => x.uri), here)) |
| 48 | emptyIt() |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | export function cut(files: DirList) { |
| 53 | state.clip = files |
| 54 | if (files.length) |
| 55 | return toast(t('after_cut', "Your selection is now in the clipboard.\nGo to destination folder to paste."), 'info') |
| 56 | } |
| 57 | |
| 58 | export function moveFiles(uri_from: string[], uri_to: string) { |
| 59 | return apiCall('move_files', { uri_from, uri_to }).then(res => { |
| 60 | const bad = _.sumBy(res.errors, x => x ? 1 : 0) |
| 61 | const msg = t(['move_results', 'good_bad'], { bad, good: uri_from.length - bad }, "{good} moved{bad,plural, =0{} other{, # failed}}") |
| 62 | if (!bad) |
| 63 | toast(msg, 'success') |
| 64 | else |
| 65 | alertDialog(h(Fragment, {}, |
| 66 | msg, |
| 67 | h('ul', {}, res.errors.map(((e: any, i: number) => { |
| 68 | e = xlate(e, HTTP_MESSAGES) |
| 69 | return e && h('li', {}, decodeURI(uri_from[i]) + ': ' + e) |
| 70 | }))), |
| 71 | ), 'warning') |
| 72 | reloadList() |
| 73 | return true |
| 74 | }, e => void alertDialog(e)) |
| 75 | } |