import * as React from "react"; import { library } from '@fortawesome/fontawesome-svg-core'; import { faTasks, 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, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as rp from 'request-promise'; import { Doc, DocListCast, FieldResult } from '../fields/Doc'; import { Id } from '../fields/FieldSymbols'; import { FieldValue, Cast, StrCast } from '../fields/Types'; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { emptyPath, emptyFunction, returnFalse, returnOne, returnTrue, returnZero, Utils } from '../Utils'; import { DocServer } from '../client/DocServer'; import { Docs } from '../client/documents/Documents'; import { Scripting } from '../client/util/Scripting'; import { DocumentView } from '../client/views/nodes/DocumentView'; import { Transform } from '../client/util/Transform'; import { InkingControl } from '../client/views/InkingControl'; import "./MobileInterface.scss"; import "./MobileMenu.scss"; import { DocumentManager } from '../client/util/DocumentManager'; import SettingsManager from '../client/util/SettingsManager'; import { Uploader } from "./ImageUpload"; import { DockedFrameRenderer } from '../client/views/collections/CollectionDockingView'; import { InkTool } from '../fields/InkField'; import { listSpec } from '../fields/Schema'; import { nullAudio, WebField } from '../fields/URLField'; library.add(faTasks, 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, faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft); @observer export class MobileInterface extends React.Component { @observable static Instance: MobileInterface; @computed private get userDoc() { return Doc.UserDoc(); } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } @computed private get activeContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } // @observable private currentView: "main" | "ink" | "upload" = "main"; @observable private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc); @observable private renderView?: () => JSX.Element; @observable private sidebarActive = true; public _activeDoc: Doc = this.mainDoc; // private inkDoc?: Doc; public drawingInk: boolean = false; // private _uploadDoc: Doc = this.userDoc; private _child: Doc | null = null; private _parents: Array = []; private _menu: Doc = this.mainDoc; private _open: boolean = false; private _library: Doc = Cast(this.userDoc.myWorkspaces, Doc) as Doc; constructor(props: Readonly<{}>) { super(props); MobileInterface.Instance = this; } @action componentDidMount = () => { library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer, faThumbtack]); if (this.userDoc && !this.mainContainer) { this.userDoc.activeMobile = this.mainDoc; } } @action switchCurrentView = (doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) => { if (!this.userDoc) return; this.userDoc.activeMobile = doc(this.userDoc); onSwitch && onSwitch(); this.renderView = renderView; } onSwitchInking = () => { InkingControl.Instance.switchTool(InkTool.Pen); MobileInterface.Instance.drawingInk = true; DocServer.Mobile.dispatchOverlayTrigger({ enableOverlay: true, width: window.innerWidth, height: window.innerHeight }); } onSwitchUpload = async () => { let width = 300; let height = 300; const res = await rp.get(Utils.prepend("/getUserDocumentId")); // get width and height of the collection doc if (this.mainContainer) { const data = Cast(this.mainContainer.data, listSpec(Doc)); if (data) { const collectionDoc = await data[1]; // this should be the collection doc since the positions should be locked const docView = DocumentManager.Instance.getDocumentView(collectionDoc); if (docView) { width = docView.nativeWidth ? docView.nativeWidth : 300; height = docView.nativeHeight ? docView.nativeHeight : 300; } } } DocServer.Mobile.dispatchOverlayTrigger({ enableOverlay: true, width: width, height: height, text: "Documents uploaded from mobile will show here", }); } back = () => { const doc = Cast(this._parents.pop(), Doc) as Doc; if (doc === Cast(this._menu, Doc) as Doc) { this._child = null; this.userDoc.activeMobile = this.mainDoc; } else { if (doc) { this._child = doc; this.switchCurrentView((userDoc: Doc) => doc); } } if (doc) { this._activeDoc = doc; } } returnHome = () => { this._parents = []; this._activeDoc = this._menu; this.switchCurrentView((userDoc: Doc) => this._menu); this._child = null; } displayWorkspaces = () => { if (this.mainContainer) { const backgroundColor = () => "white"; return (
window.screen.width} PanelHeight={() => window.screen.height} renderDepth={0} focus={emptyFunction} backgroundColor={backgroundColor} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} />
); } } handleClick(doc: Doc) { const children = DocListCast(doc.data); if (doc.type !== "collection") { this._parents.push(this._activeDoc); this._activeDoc = doc; this.switchCurrentView((userDoc: Doc) => doc); this.toggleSidebar(); } else if (doc.type === "collection" && children.length === 0) { console.log("This collection has no children"); } else { this._parents.push(this._activeDoc); this._activeDoc = doc; this.switchCurrentView((userDoc: Doc) => doc); this._child = doc; } // let sidebar = document.getElementById("sidebar") as HTMLElement; // sidebar.classList.toggle('active'); } createPathname = () => { let pathname = ""; this._parents.map((doc: Doc, index: any) => { if (doc === this.mainDoc) { pathname = pathname + doc.title; } else { pathname = pathname + " > " + doc.title; } }); if (this._activeDoc === this.mainDoc) { pathname = pathname + this._activeDoc.title; } else { pathname = pathname + " > " + this._activeDoc.title; } return pathname; } @action toggleSidebar = () => this.sidebarActive = !this.sidebarActive openLibrary() { this._activeDoc = this.mainDoc; this.switchCurrentView(() => this.mainDoc); this._child = this._library; } renderDefaultContent = () => { const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc; const buttons = DocListCast(this._child ? this._child.data : workspaces.data).map((doc: Doc, index: any) => { return (
this.handleClick(doc)}>{doc.title}
{doc.type}
); }); return ( <>
{this.sidebarActive ? StrCast(this._activeDoc.title) : "Menu"}
{this.createPathname()}
{this._child ? <>
{buttons}
Home
: <> {buttons} {/*
Library
*/}
Record Audio
Presentation
SettingsManager.Instance.open()}>Settings
}
{this._child ? null :
{this.renderView}
} ); } pinToPresentation = () => { // Only making button available if it is an image if (this._activeDoc.type === "image") { const isPinned = this._activeDoc && Doc.isDocPinned(this._activeDoc); return
{ if (isPinned) { DockedFrameRenderer.UnpinDoc(this._activeDoc); } else { DockedFrameRenderer.PinDoc(this._activeDoc); } }}>
; } } recordAudio = async () => { // upload to server with known URL this._parents.push(this._activeDoc); const audioDoc = Cast(Docs.Create.AudioDocument(nullAudio, { _width: 200, _height: 100, title: "mobile audio" }), Doc) as Doc; if (audioDoc) { console.log("audioClicked: " + audioDoc.title); this._activeDoc = audioDoc; this.switchCurrentView((userDoc: Doc) => audioDoc); this.toggleSidebar(); } const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; if (audioRightSidebar) { console.log(audioRightSidebar.title); const data = Cast(audioRightSidebar.data, listSpec(Doc)); if (data) { data.push(audioDoc); } } } openDefaultPresentation = () => { this._parents.push(this._activeDoc); const presentation = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; if (presentation) { console.log("presentation clicked: " + presentation.title); this._activeDoc = presentation; this.switchCurrentView((userDoc: Doc) => presentation); this.toggleSidebar(); } } // mobileHome = () => { // return ( //
//
//
//
//
//
//
//
//
//
//
//
// ); // } renderActiveCollection = (userDoc: Doc) => { if (this.activeContainer) { const active = Cast(this.activeContainer.data, listSpec(Doc)); if (active) { return (
HELLO!
); } } } onBack = (e: React.MouseEvent) => { this.switchCurrentView((userDoc: Doc) => this.mainDoc); InkingControl.Instance.switchTool(InkTool.None); // TODO: switch to previous tool DocServer.Mobile.dispatchOverlayTrigger({ enableOverlay: false, width: window.innerWidth, height: window.innerHeight }); // this.inkDoc = undefined; this.drawingInk = false; } shiftLeft = (e: React.MouseEvent) => { DocServer.Mobile.dispatchOverlayPositionUpdate({ dx: -10 }); e.preventDefault(); e.stopPropagation(); } shiftRight = (e: React.MouseEvent) => { DocServer.Mobile.dispatchOverlayPositionUpdate({ dx: 10 }); e.preventDefault(); e.stopPropagation(); } panelHeight = () => window.innerHeight; panelWidth = () => window.innerWidth; //WAS 3 //WAS 1 upload = async (e: React.MouseEvent) => { if (this.mainContainer) { const data = Cast(this.mainContainer.data, listSpec(Doc)); if (data) { const collectionDoc = await data[1]; //this should be the collection doc since the positions should be locked const children = DocListCast(collectionDoc.data); const uploadDoc = children.length === 1 ? children[0] : Docs.Create.StackingDocument(children, { title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true, _width: 300, _height: 300 }); if (uploadDoc) { DocServer.Mobile.dispatchMobileDocumentUpload({ docId: uploadDoc[Id], }); } } } e.stopPropagation(); e.preventDefault(); } addWebToCollection = async () => { let url = "https://en.wikipedia.org/wiki/Hedgehog"; if (this.mainContainer) { const data = Cast(this.mainContainer.data, listSpec(Doc)); if (data) { const webDoc = await data[0]; const urlField: FieldResult = Cast(webDoc.data, WebField); url = urlField ? urlField.url.toString() : "https://en.wikipedia.org/wiki/Hedgehog"; } } Docs.Create.WebDocument(url, { _width: 300, _height: 300, title: "Mobile Upload Web Doc" }); } clearUpload = async () => { if (this.mainContainer) { const data = Cast(this.mainContainer.data, listSpec(Doc)); if (data) { const collectionDoc = await data[1]; const children = DocListCast(collectionDoc.data); children.forEach(doc => { }); // collectionDoc[data] = new List(); } } } onDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); } render() { // const content = this.currentView === "main" ? this.mainContent : // this.currentView === "ink" ? this.inkContent : // this.currentView === "upload" ? this.uploadContent : <>; return (
{/* {this.renderView ? this.renderView() : this.renderDefaultContent()} */} {/* */} {this.displayWorkspaces()} {this.pinToPresentation()} {/* */} {/* */} {/* */}
{this.renderDefaultContent()}
{/* */} {/* */} {/* */} {/* */}
); } } Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); }); // WAS 2 // 1 // renderUploadContent() { // if (this.mainContainer) { // return ( //
//
// // {/* */} // {/* */} // //
// window.screen.width} // PanelHeight={() => window.screen.height} // renderDepth={0} // focus={emptyFunction} // backgroundColor={returnEmptyString} // parentActive={returnTrue} // whenActiveChanged={emptyFunction} // bringToFront={emptyFunction} // ContainingCollectionView={undefined} // ContainingCollectionDoc={undefined} /> //
// ); // } // } // 2 // Scripting.addGlobal(function onSwitchMobileInking() { return MobileInterface.Instance.onSwitchInking(); }); // Scripting.addGlobal(function renderMobileInking() { return MobileInterface.Instance.renderInkingContent(); }); // Scripting.addGlobal(function onSwitchMobileUpload() { return MobileInterface.Instance.onSwitchUpload(); }); // Scripting.addGlobal(function renderMobileUpload() { return MobileInterface.Instance.renderUploadContent(); }); // Scripting.addGlobal(function addWebToMobileUpload() { return MobileInterface.Instance.addWebToCollection(); }); // 3 // renderInkingContent = () => { // console.log("rendering inking content"); // // TODO: support panning and zooming // // TODO: handle moving of ink strokes // if (this.mainContainer) { // return ( //
//
//
// //
//
// //
//
// // //
//
// // //
// ); // } // }