diff --git a/client/assets/img/upload_white.svg b/client/assets/img/upload_white.svg new file mode 100644 index 00000000..9ce5df8b --- /dev/null +++ b/client/assets/img/upload_white.svg @@ -0,0 +1,68 @@ + + diff --git a/client/components/icon.js b/client/components/icon.js index f0828d37..3d5f8eb4 100644 --- a/client/components/icon.js +++ b/client/components/icon.js @@ -12,6 +12,7 @@ import img_pause from "../assets/img/pause.svg"; import img_error from "../assets/img/error.svg"; import img_loading_white from "../assets/img/loader_white.svg"; import img_download_white from "../assets/img/download_white.svg"; +import img_upload_white from "../assets/img/upload_white.svg"; import img_todo_white from '../assets/img/todo_white.svg'; import img_calendar_white from '../assets/img/calendar_white.svg'; import img_calendar from '../assets/img/calendar.svg'; @@ -68,6 +69,8 @@ export const Icon = (props) => { img = img_loader; }else if(props.name === 'download_white'){ img = img_download_white; + }else if(props.name === 'upload_white'){ + img = img_upload_white; }else if(props.name === 'play'){ img = img_play; }else if(props.name === 'pause'){ diff --git a/client/pages/filespage.helper.js b/client/pages/filespage.helper.js index dcfc93cf..27e081fb 100644 --- a/client/pages/filespage.helper.js +++ b/client/pages/filespage.helper.js @@ -102,22 +102,35 @@ export const onDelete = function(path, type){ .catch((err) => notify.send(err, 'error')); }; +/* + * The upload method has a few strategies: + * 1. user is coming from drag and drop + browser provides support to read entire folders + * 2. user is coming from drag and drop + browser DOES NOT provides support to read entire folders + * 3. user is coming from a upload form button as he doesn't have drag and drop with files + */ export const onUpload = function(path, e){ const MAX_POOL_SIZE = 15; let PRIOR_STATUS = {}; - if(e.dataTransfer.types && e.dataTransfer.types.length >= 0){ - if(e.dataTransfer.types[0] === "text/uri-list"){ - return - } - } - extract_upload_directory_the_way_that_works_but_non_official(e.dataTransfer.items || [], []) - .then((files) => { - if(files.length === 0){ - return extract_upload_crappy_hack_but_official_way(e.dataTransfer); + + let extractFiles = null; + if(e.dataTransfer === undefined){ // case 3 + extractFiles = extract_upload_crappy_hack_but_official_way(e.target); + } else { + if(e.dataTransfer.types && e.dataTransfer.types.length >= 0){ + if(e.dataTransfer.types[0] === "text/uri-list"){ + return } - return Promise.resolve(files); - }) - .then((files) => { + } + extractFiles = extract_upload_directory_the_way_that_works_but_non_official(e.dataTransfer.items || [], []) // case 1 + .then((files) => { + if(files.length === 0){ // case 2 + return extract_upload_crappy_hack_but_official_way(e.dataTransfer); + } + return Promise.resolve(files); + }) + } + + extractFiles.then((files) => { var failed = [], currents = []; diff --git a/client/pages/filespage.js b/client/pages/filespage.js index eeb69559..55d2c4da 100644 --- a/client/pages/filespage.js +++ b/client/pages/filespage.js @@ -9,6 +9,7 @@ import { sort, onCreate, onRename, onDelete, onUpload, onSearch, createLink } fr import { NgIf, Loader, EventReceiver, LoggedInOnly, ErrorPage } from '../components/'; import { notify, debounce, goToFiles, goToViewer, event, settings_get, settings_put } from '../helpers/'; import { BreadCrumb, FileSystem, FrequentlyAccess, Submenu } from './filespage/'; +import { MobileFileUpload } from './filespage/filezone'; import InfiniteScroll from 'react-infinite-scroller'; const PAGE_NUMBER_INIT = 2; @@ -252,6 +253,7 @@ export class FilesPage extends React.Component { +
diff --git a/client/pages/filespage/filezone.js b/client/pages/filespage/filezone.js index 309107c3..8b42af19 100644 --- a/client/pages/filespage/filezone.js +++ b/client/pages/filespage/filezone.js @@ -1,8 +1,9 @@ import React from 'react'; import PropTypes from 'prop-types'; +import ReactCSSTransitionGroup from 'react-addons-css-transition-group'; import { DropTarget } from 'react-dnd'; -import { EventEmitter } from '../../components/'; +import { EventEmitter, Icon } from '../../components/'; import './filezone.scss'; @EventEmitter @@ -27,7 +28,35 @@ export class FileZone extends React.Component{ ); } } - FileZone.propTypes = { path: PropTypes.string.isRequired } + +@EventEmitter +export class MobileFileUpload extends React.Component{ + constructor(props){ + super(props); + } + + onUpload(e){ + this.props.emit("file.upload", this.props.path, e); + } + render(){ + if(/(Android|iPad|iPhone)/.test(navigator.userAgent) === false){ + return null; + } + + return ( + +
+
+ + +
+
+
+ ); + } +} diff --git a/client/pages/filespage/filezone.scss b/client/pages/filespage/filezone.scss index 21f60f52..fbefac39 100644 --- a/client/pages/filespage/filezone.scss +++ b/client/pages/filespage/filezone.scss @@ -1,3 +1,5 @@ +@import "../../assets/css/mixin.scss"; + .component_filezone{ border: 2px dashed; padding: 25px 0; @@ -9,3 +11,47 @@ border: 2px dashed var(--primary); } } + +.component_mobilefileupload{ + display: inline; + position: fixed; + bottom: 25px; + right: 25px; + + input[type="file"]{ + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; + } + input[type="file"]:focus + label, input[type="file"] + label:hover { + opacity: 0.95; + } + input[type="file"] + label { + display: inline-block; + cursor: pointer; + background: var(--color); + border-radius: 50%; + @include ripple(var(--emphasis-secondary), var(--primary)); + box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px; + + width: 50px; + height: 50px; + .component_icon{ + width: 24px; + height: 24px; + padding: 13px; + } + } +} + +.mobilefileupload-appear{ + transform: translateX(75px); + transition: transform 0.25s ease; +} +.mobilefileupload-appear-active{ + transition-delay: 0.3s; + transform: translateX(0px); +}