diff options
author | Lionel Han <47760119+IGoByJoe@users.noreply.github.com> | 2020-06-22 17:47:15 -0700 |
---|---|---|
committer | Lionel Han <47760119+IGoByJoe@users.noreply.github.com> | 2020-06-22 17:47:15 -0700 |
commit | b989082c3502e8ad5ca3a89a8459e6ac72e38ccc (patch) | |
tree | 7d1c0b09d26d6cb33555569cd164da1c7043e89e | |
parent | 6df649ae1228f191a5654e45e898880b130afd28 (diff) | |
parent | 790d41009a678f560cd3b78e86069251e494cfd1 (diff) |
pull
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 2 | ||||
-rw-r--r-- | src/client/util/SettingsManager.scss | 2 | ||||
-rw-r--r-- | src/client/views/AntimodeMenu.scss | 16 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.scss | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewChromes.scss | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss | 18 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.scss | 2 | ||||
-rw-r--r-- | src/client/views/nodes/AudioBox.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.scss | 2 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.scss | 12 | ||||
-rw-r--r-- | src/client/views/presentationview/PresElementBox.scss | 2 | ||||
-rw-r--r-- | src/mobile/AudioUpload.scss | 24 | ||||
-rw-r--r-- | src/mobile/AudioUpload.tsx | 237 | ||||
-rw-r--r-- | src/mobile/ImageUpload.scss | 15 | ||||
-rw-r--r-- | src/mobile/ImageUpload.tsx | 81 | ||||
-rw-r--r-- | src/mobile/MobileInterface.tsx | 205 | ||||
-rw-r--r-- | src/mobile/MobileMenu.scss | 39 |
17 files changed, 486 insertions, 181 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b7da4ae2f..5edb2225f 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -465,7 +465,7 @@ export class CurrentUserUtils { static setupMobileButtons(doc?: Doc, buttons?: string[]) { const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, info: string, dragFactory?: Doc }[] = [ - { title: "LIBRARY", icon: "bars", click: 'switchToLibrary()', backgroundColor: "#ffd6d6", info: "Navigate and access all of your documents within their respective collections." }, + { title: "WORKSPACES", icon: "folder-open", click: 'openWorkspaces()', backgroundColor: "#ffd6d6", info: "Access your Workspaces from your mobile, and navigate through all of your documents. " }, { title: "RECORD", icon: "microphone", click: 'openMobileAudio()', backgroundColor: "#ffbfbf", info: "Use your phone to record and upload audio onto Dash Web." }, { title: "UPLOAD", icon: "upload", click: 'uploadImageMobile()', backgroundColor: "#ff9e9e", info: "Upload images or videos from your mobile device so they can be accessed on Dash Web." }, { title: "PRESENTATION", icon: "desktop", click: 'openMobilePresentation()', backgroundColor: "#ff8080", info: "Use your phone as a remote for you presentation." }, diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss index 1eac9303b..0116c5294 100644 --- a/src/client/util/SettingsManager.scss +++ b/src/client/util/SettingsManager.scss @@ -135,7 +135,7 @@ } } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .settings-interface { background-color: whitesmoke !important; color: grey; diff --git a/src/client/views/AntimodeMenu.scss b/src/client/views/AntimodeMenu.scss index 170631422..43f45fb1c 100644 --- a/src/client/views/AntimodeMenu.scss +++ b/src/client/views/AntimodeMenu.scss @@ -41,7 +41,7 @@ } } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .antimodeMenu-cont { position: absolute; z-index: 10000; @@ -51,31 +51,31 @@ border-radius: 0px 6px 6px 6px; // overflow: hidden; display: flex; - + &.with-rows { flex-direction: column-reverse; } - + .antimodeMenu-row { display: flex; height: 100%; - width:100%; + width: 100%; } - + .antimodeMenu-button { background-color: transparent; width: 100px; height: 100px; - + &.active { background-color: #121212; } } - + .antimodeMenu-button:hover { background-color: #121212; } - + .antimodeMenu-dragger { height: 100%; transition: width .2s; diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 98efdfd23..342773db8 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -424,7 +424,7 @@ } } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .collectionStackingView .collectionStackingView-columnDragger, .collectionMasonryView .collectionStackingView-columnDragger { diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index f85cbfee2..ec2d78735 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -80,6 +80,12 @@ // margin-top: 10px; } + @media only screen and (max-device-width: 480px) { + .collectionViewBaseChrome-collapse { + display: none; + } + } + .collectionViewBaseChrome-template, .collectionViewBaseChrome-viewModes { display: grid; diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss index 72fdf5af9..4855dfea8 100644 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss +++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss @@ -33,39 +33,39 @@ } } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .antimodeMenu-button { .color-preview { width: 100%; height: 100%; } - + } - + .sketch-picker { background: #323232; - + .flexbox-fit { background: #323232; } } - + .btn-group { display: grid; grid-template-columns: auto auto; /* Make the buttons appear below each other */ } - + .btn2-group { display: block; background: #323232; grid-template-columns: auto; - + /* Make the buttons appear below each other */ .antimodeMenu-button { background: #323232; display: block; - + } } -} +}
\ No newline at end of file diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 61ce4bd13..43dd698ad 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -174,7 +174,7 @@ } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .audiobox-container, .audiobox-container-interactive { diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 2e0be1c6a..cb0582d87 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -161,7 +161,7 @@ export class AudioBox extends ViewBoxBaseComponent<FieldViewProps, AudioDocument const funcs: ContextMenuProps[] = []; funcs.push({ description: (this.layoutDoc.playOnSelect ? "Don't play" : "Play") + " when document selected", event: () => this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); + ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } stopRecording = action(() => { diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 1a31d2916..b19ddf1f5 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -224,7 +224,7 @@ } } -@media only screen and (max-width: 600px) { +@media only screen and (max-device-width: 480px) { .pdfBox .pdfBox-ui .pdfBox-settingsCont .pdfBox-settingsButton, .pdfBox-interactive .pdfBox-ui .pdfBox-settingsCont .pdfBox-settingsButton { diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index ccce6e627..1261cbfdd 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -81,7 +81,7 @@ } } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .presBox-cont .presBox-buttons { position: absolute; top: 70%; @@ -105,15 +105,13 @@ } .presBox-cont .presBox-buttons .presBox-button { - margin-right: 10px; - margin-left: 10px; + margin-top: 5%; height: 250; - width: 250; - font-size: 70; - border-radius: 25px; + width: 300; + font-size: 100; display: flex; align-items: center; - background: #323232; + background: 323232; color: white; } diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index 99fe2a3ba..79532995e 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -106,7 +106,7 @@ z-index: 2; } -@media only screen and (max-width: 1000px) { +@media only screen and (max-device-width: 480px) { .presElementBox-buttons { display: inline-flex; position: relative; diff --git a/src/mobile/AudioUpload.scss b/src/mobile/AudioUpload.scss new file mode 100644 index 000000000..9fe442e55 --- /dev/null +++ b/src/mobile/AudioUpload.scss @@ -0,0 +1,24 @@ +@import "../client/views/globalCssVariables.scss"; + +.audioUpload_cont { + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + max-width: 400px; + min-width: 400px; +} + +.audio-upload { + top: 100%; + opacity: 0; +} + +.audio-upload.active { + top: 0; + position: absolute; + z-index: 999; + height: 100vh; + width: 100vw; + opacity: 1; +}
\ No newline at end of file diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx new file mode 100644 index 000000000..7ea11ee84 --- /dev/null +++ b/src/mobile/AudioUpload.tsx @@ -0,0 +1,237 @@ +import * as ReactDOM from 'react-dom'; +import * as rp from 'request-promise'; +import { Docs } from '../client/documents/Documents'; +import "./ImageUpload.scss"; +import React = require('react'); +import { DocServer } from '../client/DocServer'; +import { observer } from 'mobx-react'; +import { observable, action } from 'mobx'; +import { Utils, emptyPath, returnFalse, emptyFunction, returnOne, returnZero, returnTrue } from '../Utils'; +import { Networking } from '../client/Network'; +import { Doc, Opt } from '../fields/Doc'; +import { Cast } from '../fields/Types'; +import { listSpec } from '../fields/Schema'; +import { List } from '../fields/List'; +import { Scripting } from '../client/util/Scripting'; +import MainViewModal from '../client/views/MainViewModal'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { nullAudio } from '../fields/URLField'; +import { Transform } from '../client/util/Transform'; +import { DocumentView } from '../client/views/nodes/DocumentView'; +import { MobileInterface } from './MobileInterface'; + +export interface ImageUploadProps { + Document: Doc; +} + +// const onPointerDown = (e: React.TouchEvent) => { +// let imgInput = document.getElementById("input_image_file"); +// if (imgInput) { +// imgInput.click(); +// } +// } +const inputRef = React.createRef<HTMLInputElement>(); + +@observer +export class AudioUpload extends React.Component { + @observable error: string = ""; + @observable status: string = ""; + @observable nm: string = "Choose files"; + @observable process: string = ""; + + onClick = async () => { + try { + await Docs.Prototypes.initialize(); + const imgPrev = document.getElementById("img_preview"); + const slab1 = document.getElementById("slab1"); + if (slab1) { + slab1.style.opacity = "1"; + } + if (imgPrev) { + const files: FileList | null = inputRef.current!.files; + const slab2 = document.getElementById("slab2"); + if (slab2) { + slab2.style.opacity = "1"; + } + if (files && files.length !== 0) { + this.process = "Uploading Files"; + for (let index = 0; index < files.length; ++index) { + const file = files[index]; + const res = await Networking.UploadFilesToServer(file); + const slab3 = document.getElementById("slab3"); + if (slab3) { + slab3.style.opacity = "1"; + } + res.map(async ({ result }) => { + const name = file.name; + if (result instanceof Error) { + return; + } + const path = Utils.prepend(result.accessPaths.agnostic.client); + let doc = null; + console.log("type: " + file.type); + if (file.type === "video/mp4") { + doc = Docs.Create.VideoDocument(path, { _nativeWidth: 200, _width: 200, title: name }); + } else if (file.type === "application/pdf") { + doc = Docs.Create.PdfDocument(path, { _width: 200, title: name }); + } else { + doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name }); + } + const slab4 = document.getElementById("slab4"); + if (slab4) { + slab4.style.opacity = "1"; + } + const res = await rp.get(Utils.prepend("/getUserDocumentId")); + if (!res) { + throw new Error("No user id returned"); + } + const field = await DocServer.GetRefField(res); + let pending: Opt<Doc>; + if (field instanceof Doc) { + pending = await Cast(field.mobileUpload, Doc); + } + if (pending) { + const data = await Cast(pending.data, listSpec(Doc)); + if (data) { + data.push(doc); + } else { + pending.data = new List([doc]); + } + this.status = "finished"; + const slab5 = document.getElementById("slab5"); + if (slab5) { + slab5.style.opacity = "1"; + } + this.process = "File " + (index + 1).toString() + " Uploaded"; + const slab6 = document.getElementById("slab6"); + if (slab6) { + slab6.style.opacity = "1"; + } + const slab7 = document.getElementById("slab7"); + if (slab7) { + slab7.style.opacity = "1"; + } + + } + }); + } + } else { + this.process = "No file selected"; + } + setTimeout(this.clearUpload, 3000); + } + } catch (error) { + this.error = JSON.stringify(error); + } + } + + // Updates label after a files is selected (so user knows a file is uploaded) + inputLabel = async () => { + const files: FileList | null = inputRef.current!.files; + await files; + if (files && files.length === 1) { + console.log(files); + this.nm = files[0].name; + } else if (files && files.length > 1) { + console.log(files.length); + this.nm = files.length.toString() + " files selected"; + } + } + + @action + clearUpload = () => { + const slab1 = document.getElementById("slab1"); + if (slab1) { + slab1.style.opacity = "0.4"; + } + const slab2 = document.getElementById("slab2"); + if (slab2) { + slab2.style.opacity = "0.4"; + } + const slab3 = document.getElementById("slab3"); + if (slab3) { + slab3.style.opacity = "0.4"; + } + const slab4 = document.getElementById("slab4"); + if (slab4) { + slab4.style.opacity = "0.4"; + } + const slab5 = document.getElementById("slab5"); + if (slab5) { + slab5.style.opacity = "0.4"; + } + const slab6 = document.getElementById("slab6"); + if (slab6) { + slab6.style.opacity = "0.4"; + } + const slab7 = document.getElementById("slab7"); + if (slab7) { + slab7.style. + opacity = "0.4"; + } + this.nm = "Choose files"; + + if (inputRef.current) { + inputRef.current.value = ""; + } + this.process = ""; + console.log(inputRef.current!.files); + } + + + + private get uploadInterface() { + const audioDoc = Cast(Docs.Create.AudioDocument(nullAudio, { title: "mobile audio" }), Doc) as Doc; + + return ( + <div className="imgupload_cont"> + <div className="closeUpload" onClick={MobileInterface.Instance.toggleAudio}> + <FontAwesomeIcon icon="window-close" size={"lg"} /> + </div> + <DocumentView + Document={audioDoc} + DataDoc={undefined} + LibraryPath={emptyPath} + addDocument={returnFalse} + addDocTab={returnFalse} + pinToPres={emptyFunction} + rootSelected={returnFalse} + removeDocument={undefined} + onClick={undefined} + ScreenToLocalTransform={Transform.Identity} + ContentScaling={returnOne} + PanelWidth={() => 1000} + PanelHeight={() => 1000} + NativeHeight={returnZero} + NativeWidth={returnZero} + renderDepth={0} + focus={emptyFunction} + backgroundColor={() => "white"} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + /> + </div> + ); + } + + @observable private dialogueBoxOpacity = 1; + @observable private overlayOpacity = 0.4; + + render() { + return ( + <MainViewModal + contents={this.uploadInterface} + isDisplayed={true} + interactive={true} + dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} + overlayDisplayedOpacity={this.overlayOpacity} + /> + ); + } + +} + + diff --git a/src/mobile/ImageUpload.scss b/src/mobile/ImageUpload.scss index 95c0c2680..b64aac338 100644 --- a/src/mobile/ImageUpload.scss +++ b/src/mobile/ImageUpload.scss @@ -55,6 +55,7 @@ background-color: black; display: inline-block; margin: 10px; + margin-top: 30px; width: 100%; border-radius: 10px; } @@ -106,16 +107,15 @@ .closeUpload { position: absolute; border-radius: 10px; - top: 39.7%; - color: grey; - font-size: 40; - left: 65.8%; + top: 3; + color: black; + font-size: 30; + right: 3; z-index: 1002; padding: 0px 3px; - background: aliceblue; + background: rgba(0, 0, 0, 0); transition: 0.5s ease all; - border: 3px solid; - border-color: black; + border: 0px solid; } .loadingImage { @@ -131,4 +131,5 @@ border-radius: 20px; opacity: 0.3; background-color: black; + transition: all 2s, opacity 1.5s; }
\ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 0b63c42be..b712d52cc 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -15,6 +15,8 @@ import { List } from '../fields/List'; import { Scripting } from '../client/util/Scripting'; import MainViewModal from '../client/views/MainViewModal'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { MobileInterface } from './MobileInterface'; +import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; export interface ImageUploadProps { Document: Doc; @@ -40,25 +42,22 @@ export class Uploader extends React.Component<ImageUploadProps> { const col = this.props.Document; await Docs.Prototypes.initialize(); const imgPrev = document.getElementById("img_preview"); + // Slab 1 const slab1 = document.getElementById("slab1"); - if (slab1) { - slab1.style.opacity = "1"; - } + if (slab1) slab1.style.opacity = "1"; if (imgPrev) { const files: FileList | null = inputRef.current!.files; + // Slab 2 const slab2 = document.getElementById("slab2"); - if (slab2) { - slab2.style.opacity = "1"; - } + if (slab2) slab2.style.opacity = "1"; if (files && files.length !== 0) { this.process = "Uploading Files"; for (let index = 0; index < files.length; ++index) { const file = files[index]; const res = await Networking.UploadFilesToServer(file); + // Slab 3 const slab3 = document.getElementById("slab3"); - if (slab3) { - slab3.style.opacity = "1"; - } + if (slab3) slab3.style.opacity = "1"; res.map(async ({ result }) => { const name = file.name; if (result instanceof Error) { @@ -68,16 +67,15 @@ export class Uploader extends React.Component<ImageUploadProps> { let doc = null; console.log("type: " + file.type); if (file.type === "video/mp4") { - doc = Docs.Create.VideoDocument(path, { _nativeWidth: 200, _width: 200, title: name }); + doc = Docs.Create.VideoDocument(path, { _nativeWidth: 400, _width: 400, title: name }); } else if (file.type === "application/pdf") { - doc = Docs.Create.PdfDocument(path, { _width: 200, title: name }); + doc = Docs.Create.PdfDocument(path, { _nativeWidth: 400, _width: 400, title: name }); } else { - doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name }); + doc = Docs.Create.ImageDocument(path, { _nativeWidth: 400, _width: 400, title: name }); } + // Slab 4 const slab4 = document.getElementById("slab4"); - if (slab4) { - slab4.style.opacity = "1"; - } + if (slab4) slab4.style.opacity = "1"; const res = await rp.get(Utils.prepend("/getUserDocumentId")); if (!res) { throw new Error("No user id returned"); @@ -93,26 +91,16 @@ export class Uploader extends React.Component<ImageUploadProps> { } if (pending) { const data = await Cast(pending.data, listSpec(Doc)); - if (data) { - data.push(doc); - } else { - pending.data = new List([doc]); - } + if (data) data.push(doc); + else pending.data = new List([doc]); this.status = "finished"; const slab5 = document.getElementById("slab5"); - if (slab5) { - slab5.style.opacity = "1"; - } + if (slab5) slab5.style.opacity = "1"; this.process = "File " + (index + 1).toString() + " Uploaded"; const slab6 = document.getElementById("slab6"); - if (slab6) { - slab6.style.opacity = "1"; - } + if (slab6) slab6.style.opacity = "1"; const slab7 = document.getElementById("slab7"); - if (slab7) { - slab7.style.opacity = "1"; - } - + if (slab7) slab7.style.opacity = "1"; } }); } @@ -142,33 +130,19 @@ export class Uploader extends React.Component<ImageUploadProps> { @action clearUpload = () => { const slab1 = document.getElementById("slab1"); - if (slab1) { - slab1.style.opacity = "0.4"; - } + if (slab1) slab1.style.opacity = "0.4"; const slab2 = document.getElementById("slab2"); - if (slab2) { - slab2.style.opacity = "0.4"; - } + if (slab2) slab2.style.opacity = "0.4"; const slab3 = document.getElementById("slab3"); - if (slab3) { - slab3.style.opacity = "0.4"; - } + if (slab3) slab3.style.opacity = "0.4"; const slab4 = document.getElementById("slab4"); - if (slab4) { - slab4.style.opacity = "0.4"; - } + if (slab4) slab4.style.opacity = "0.4"; const slab5 = document.getElementById("slab5"); - if (slab5) { - slab5.style.opacity = "0.4"; - } + if (slab5) slab5.style.opacity = "0.4"; const slab6 = document.getElementById("slab6"); - if (slab6) { - slab6.style.opacity = "0.4"; - } + if (slab6) slab6.style.opacity = "0.4"; const slab7 = document.getElementById("slab7"); - if (slab7) { - slab7.style.opacity = "0.4"; - } + if (slab7) slab7.style.opacity = "0.4"; this.nm = "Choose files"; if (inputRef.current) { @@ -183,6 +157,9 @@ export class Uploader extends React.Component<ImageUploadProps> { private get uploadInterface() { return ( <div className="imgupload_cont"> + <div className="closeUpload" onClick={MobileInterface.Instance.toggleUpload}> + <FontAwesomeIcon icon="window-close" size={"lg"} /> + </div> <input type="file" accept="application/pdf, video/*,image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel} multiple></input> <label className="file" id="label" htmlFor="input_image_file">{this.nm}</label> <div className="upload_label" onClick={this.onClick}> @@ -223,5 +200,3 @@ export class Uploader extends React.Component<ImageUploadProps> { } } - - diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 63c7873f4..ceda74da2 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTasks, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, + faTasks, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, @@ -25,6 +25,7 @@ import "./MobileInterface.scss"; import "./MobileMenu.scss"; import "./MobileHome.scss"; import "./ImageUpload.scss"; +import "./AudioUpload.scss"; import { DocumentManager } from '../client/util/DocumentManager'; import SettingsManager from '../client/util/SettingsManager'; import { Uploader } from "./ImageUpload"; @@ -39,8 +40,9 @@ import { RadialMenu } from "../client/views/nodes/RadialMenu"; import { UndoManager } from "../client/util/UndoManager"; import { MainView } from "../client/views/MainView"; import { List } from "../fields/List"; +import { AudioUpload } from "./AudioUpload"; -library.add(faTasks, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, +library.add(faTasks, faFolderOpen, faAngleDoubleLeft, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, @@ -54,17 +56,18 @@ export class MobileInterface extends React.Component { @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } @observable private mainDoc: any = CurrentUserUtils.setupActiveMobileMenu(this.userDoc); @observable private renderView?: () => JSX.Element; - @observable private sidebarActive: boolean = false; - @observable private imageUploadActive: boolean = false; - @observable private menuListView: boolean = false; - @observable private _ink: boolean = false; - - public _activeDoc: Doc = this.mainDoc; - public _homeDoc: Doc = this.mainDoc; - private _homeMenu: boolean = true; - private _child: Doc | null = null; - private _parents: Array<Doc> = []; - private _library: Doc = CurrentUserUtils.setupLibrary(this.userDoc); + @observable private sidebarActive: boolean = false; //to toggle sidebar display + @observable private imageUploadActive: boolean = false; //to toggle image upload + @observable private audioUploadActive: boolean = false; + @observable private menuListView: boolean = false; //to switch between menu view (list / icon) + @observable private _ink: boolean = false; //toggle whether ink is being dispalyed + + public _activeDoc: Doc = this.mainDoc; // doc updated as the active mobile page is updated (initially home menu) + public _homeDoc: Doc = this.mainDoc; // home menu as a document + private _homeMenu: boolean = true; // to determine whether currently at home menu + private _child: Doc | null = null; // currently selected document + private _parents: Array<Doc> = []; // array of parent docs (for pathbar) + private _library: Doc = CurrentUserUtils.setupLibrary(this.userDoc); // to access documents in Dash Web constructor(props: Readonly<{}>) { super(props); @@ -118,8 +121,15 @@ export class MobileInterface extends React.Component { this.sidebarActive = true; } + openWorkspaces = () => { + this._parents.push(this._activeDoc); + this.switchCurrentView((userDoc: Doc) => this._library); + this._activeDoc = this._library; + this._homeMenu = false; + } + /** - * Back method for navigating + * Back method for navigating through items */ back = () => { const header = document.getElementById("header") as HTMLElement; @@ -182,7 +192,7 @@ export class MobileInterface extends React.Component { if (this.mainContainer) { const backgroundColor = () => "white"; return ( - <div style={{ position: "relative", top: '200px', height: `calc(100% - 350px)`, width: "100%", left: "0%" }}> + <div style={{ position: "relative", top: '198px', height: `calc(100% - 350px)`, width: "100%", left: "0%" }}> <DocumentView Document={this.mainContainer} DataDoc={undefined} @@ -213,6 +223,11 @@ export class MobileInterface extends React.Component { } } + /** + * Note: window.innerWidth and window.screen.width compute different values. + * window.screen.width is the display size, however window.innerWidth is the + * display resolution which computes differently. + */ returnWidth = () => window.innerWidth; //The windows width returnHeight = () => (window.innerHeight - 300); //Calculating the windows height (-300 to account for topbar) @@ -223,13 +238,8 @@ export class MobileInterface extends React.Component { */ handleClick = async (doc: Doc) => { const children = DocListCast(doc.data); - if (doc.type !== "collection" && this.sidebarActive) { - this._parents.push(this._activeDoc); - this._activeDoc = doc; - this.switchCurrentView((userDoc: Doc) => doc); - this._homeMenu = false; - this.toggleSidebar(); - } else if (doc.type === "collection" && children.length === 0) console.log("This collection has no children"); + if (doc.type !== "collection" && this.sidebarActive) this.openFromSidebar(doc); + else if (doc.type === "collection" && children.length === 0) this.openFromSidebar(doc); else { this._parents.push(this._activeDoc); this._activeDoc = doc; @@ -239,6 +249,15 @@ export class MobileInterface extends React.Component { } } + openFromSidebar = (doc: Doc) => { + this._parents.push(this._activeDoc); + this._activeDoc = doc; + this.switchCurrentView((userDoc: Doc) => doc); + this._homeMenu = false; + this._child = doc; //? + this.toggleSidebar(); + } + /** * Handles creation of array which is then rendered in renderPathbar() */ @@ -350,14 +369,6 @@ export class MobileInterface extends React.Component { </div> </div> {this.renderPathbar()} - <div className="sidebar" id="sidebar"> - <div className="sidebarButtons"> - <div - className="item" - onClick={() => MainView.Instance?.createNewWorkspace()}>Create New Workspace - </div> - </div> - </div> </div> ); } @@ -377,6 +388,7 @@ export class MobileInterface extends React.Component { <div className="item-title"> {doc.title} </div> <div className="item-type">{doc.type}</div> <FontAwesomeIcon className="right" icon="angle-right" size="lg" /> + <FontAwesomeIcon className="open" onClick={() => this.openFromSidebar(doc)} icon="external-link-alt" size="lg" /> </div>); } }); @@ -398,9 +410,13 @@ export class MobileInterface extends React.Component { {this._child ? <> {buttons} - <div className="item" key="home" onClick={this.returnMain}> - Return to library - </div> + <div + className="item" key="home" + onClick={this.returnMain} + style={{ opacity: 0.7 }}> + <FontAwesomeIcon className="right" icon="angle-double-left" size="lg" /> + <div className="item-type">Return to workspaces</div> + </div> </> : <> {buttons} @@ -455,7 +471,7 @@ export class MobileInterface extends React.Component { return <div className="docButton" title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} style={{ backgroundColor: "black", color: "white" }} - onClick={this.uploadAudio} + // onClick={this.uploadAudio} > <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="upload" /> @@ -492,21 +508,45 @@ export class MobileInterface extends React.Component { } } + undo = () => { + if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc.title !== "WORKSPACES") { + return (<> + <div className="docButton" + style={{ backgroundColor: "black", color: "white" }} + id="undoButton" + title="undo" + onClick={(e: React.MouseEvent) => { + UndoManager.Undo(); + e.stopPropagation(); + }}> + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="undo-alt" /> + </div> + </>); + } + } + + redo = () => { + if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc.title !== "WORKSPACES") { + return (<> + <div className="docButton" + style={{ backgroundColor: "black", color: "white" }} + id="undoButton" + title="redo" + onClick={(e: React.MouseEvent) => { + UndoManager.Redo(); + e.stopPropagation(); + }}> + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="redo-alt" /> + </div> + </>); + } + } + // Button for switching into ink mode drawInk = () => { if (this._activeDoc._viewType === "docking") { return ( <> - {/* <div className="docButton" - id="undoButton" - title="undo" - onClick={(e: React.MouseEvent) => { - UndoManager.Undo(); - e.stopPropagation(); - }}> - <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="undo-alt" - /> - </div> */} <div className="docButton" id="inkButton" title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} @@ -514,23 +554,29 @@ export class MobileInterface extends React.Component { <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="pen-nib" /> </div> - {/* <div className="docButton" - id="redoButton" - title="redo" - onClick={(e: React.MouseEvent) => { - UndoManager.Redo(); - e.stopPropagation(); - }}> - <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="redo-alt" + </>); + } + } + + // Mobile doc button for uploading + upload = () => { + if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc) { + return ( + <> + <div className="docButton" + id="uploadButton" + title={"uploadFile"} + onClick={this.toggleUpload}> + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="upload" /> - </div> */} + </div> </>); } } // Button to download images on the mobile downloadDocument = () => { - if (this._activeDoc.type === "image") { + if (this._activeDoc.type === "image" || this._activeDoc.type === "pdf" || this._activeDoc.type === "video") { const url = this._activeDoc["data-path"]?.toString(); return <div className="docButton" title={"Download Image"} @@ -559,24 +605,21 @@ export class MobileInterface extends React.Component { } } - // Pushing the audio doc onto Dash Web through the right side bar - uploadAudio = () => { - const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; - const audioDoc = this._activeDoc; - const data = Cast(audioRightSidebar.data, listSpec(Doc)); + // // Pushing the audio doc onto Dash Web through the right side bar + // uploadAudio = () => { + // const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; + // const audioDoc = this._activeDoc; + // const data = Cast(audioRightSidebar.data, listSpec(Doc)); - if (data) { - data.push(audioDoc); - } - } - - panelHeight = () => window.innerHeight; - panelWidth = () => window.innerWidth; + // if (data) { + // data.push(audioDoc); + // } + // } // Button for pinning images to presentation pinToPresentation = () => { // Only making button available if it is an image - if (this._activeDoc.type === "image") { + if (!(this._activeDoc.type === "collection" || this._activeDoc.type === "presentation")) { const isPinned = this._activeDoc && Doc.isDocPinned(this._activeDoc); return <div className="docButton" title={Doc.isDocPinned(this._activeDoc) ? "Unpin from presentation" : "Pin to presentation"} @@ -611,7 +654,7 @@ export class MobileInterface extends React.Component { } } - // Logics for switching the menu into the icons + // Logic for switching the menu into the icons @action changeToIconView = () => { if (this._homeDoc._viewType = "stacking") { @@ -635,7 +678,7 @@ export class MobileInterface extends React.Component { } } - // Logics for switching the menu into the stacking view + // Logic for switching the menu into the stacking view @action changeToListView = () => { if (this._homeDoc._viewType = "masonry") { @@ -674,6 +717,10 @@ export class MobileInterface extends React.Component { @action toggleUpload = () => this.imageUploadActive = !this.imageUploadActive + // For toggling image upload pop up + @action + toggleAudio = () => this.audioUploadActive = !this.audioUploadActive + @action toggleUploadInCollection = () => { const button = document.getElementById("imageButton") as HTMLElement; @@ -703,7 +750,7 @@ export class MobileInterface extends React.Component { doc = this._activeDoc; toggle = this.toggleUploadInCollection; } else { - doc = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc + doc = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; toggle = this.toggleUpload; } return ( @@ -735,7 +782,7 @@ export class MobileInterface extends React.Component { onClick={this.toggleUpload}> <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="upload" /> - </div> + </div>; } } @@ -756,18 +803,22 @@ export class MobileInterface extends React.Component { <SettingsManager /> <div className={`image-upload ${this.imageUploadActive ? "active" : ""}`}> {this.uploadImage()} - + </div> + <div className={`audio-upload ${this.audioUploadActive ? "active" : ""}`}> + <AudioUpload /> </div> {this.switchMenuView()} {this.inkMenu()} - <GestureOverlay> <div className="docButtonContainer"> - {this.uploadImageButton()} {this.pinToPresentation()} {this.downloadDocument()} + {this.undo()} {this.drawInk()} - {this.uploadAudioButton()} + {this.redo()} + {/* {this.upload()} */} + {this.uploadImageButton()} + {/* {this.uploadAudioButton()} */} </div> {this.displayWorkspaces()} {this.renderDefaultContent()} @@ -783,8 +834,8 @@ export class MobileInterface extends React.Component { Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); }); Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); }); Scripting.addGlobal(function toggleMobileSidebar() { return MobileInterface.Instance.toggleSidebar(); }); -Scripting.addGlobal(function openMobileAudio() { return MobileInterface.Instance.recordAudio(); }); +Scripting.addGlobal(function openMobileAudio() { return MobileInterface.Instance.toggleAudio(); }); Scripting.addGlobal(function openMobileSettings() { return SettingsManager.Instance.open(); }); -Scripting.addGlobal(function switchToLibrary() { return MobileInterface.Instance.switchToLibrary(); }); +Scripting.addGlobal(function openWorkspaces() { return MobileInterface.Instance.openWorkspaces(); }); Scripting.addGlobal(function uploadImageMobile() { return MobileInterface.Instance.toggleUpload(); }); Scripting.addGlobal(function switchToMobileUploads() { return MobileInterface.Instance.switchToMobileUploads(); }); diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss index 6304ff5e4..53bc48034 100644 --- a/src/mobile/MobileMenu.scss +++ b/src/mobile/MobileMenu.scss @@ -19,7 +19,6 @@ body { width: 100vw; height: $navbar-height; background-color: whitesmoke; - border-bottom: 5px solid black; z-index: 150; } @@ -175,6 +174,11 @@ body { z-index: 200; } +.open { + right: 20px; + position: absolute; +} + .left { width: 100%; height: 100%; @@ -216,14 +220,17 @@ body { .back { position: absolute; - top: 44%; left: 42px; - background-color: black; + top: 0; + background: #1a1a1a; width: 50px; - height: 50px; + height: 100%; + display: flex; + justify-content: center; text-align: center; + flex-direction: column; + align-items: center; border-radius: 10px; - transform: translate(0, -50%); font-size: 25px; user-select: none; z-index: 100; @@ -238,7 +245,7 @@ body { border-radius: 0px; width: 100%; height: 80px; - transition: all 400ms ease 50ms; + overflow: hidden; } .pathname { @@ -262,15 +269,17 @@ body { .docButton { position: relative; width: 100px; + display: flex; height: 100px; font-size: 70px; - padding: 5px; text-align: center; - border-style: solid; - border-radius: 50px; - border-width: 5px; + border: 3px solid black; margin: 20px; z-index: 100; + border-radius: 100%; + justify-content: center; + flex-direction: column; + align-items: center; } .docButtonContainer { @@ -284,14 +293,19 @@ body { .scrollmenu { overflow: auto; + width: 100%; + height: 100%; white-space: nowrap; + display: inline-flex; } .pathbarItem { position: relative; - display: inline-flex; + display: flex; + align-items: center; color: whitesmoke; text-align: center; + justify-content: center; user-select: none; transform: translate(100px, 0px); font-size: 30px; @@ -304,7 +318,6 @@ body { text-align: center; height: 50px; padding: 10px; - background-color: rgb(48, 40, 40); font-size: 30px; border-radius: 10px; text-transform: uppercase; @@ -314,7 +327,7 @@ body { .pathIcon { - transform: translate(0px, 8px); + transform: translate(0px, 0px); position: relative; } |