diff options
-rw-r--r-- | deploy/mobile/image.html | 5 | ||||
-rw-r--r-- | package-lock.json | 84 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 101 | ||||
-rw-r--r-- | src/client/util/SettingsManager.scss | 31 | ||||
-rw-r--r-- | src/client/views/GestureOverlay.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionStackingView.scss | 16 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/nodes/PresBox.scss | 65 | ||||
-rw-r--r-- | src/client/views/presentationview/PresElementBox.scss | 97 | ||||
-rw-r--r-- | src/mobile/ImageUpload.scss | 111 | ||||
-rw-r--r-- | src/mobile/ImageUpload.tsx | 190 | ||||
-rw-r--r-- | src/mobile/MobileHome.scss | 101 | ||||
-rw-r--r-- | src/mobile/MobileInkOverlay.tsx | 4 | ||||
-rw-r--r-- | src/mobile/MobileInterface.scss | 9 | ||||
-rw-r--r-- | src/mobile/MobileInterface.tsx | 1906 | ||||
-rw-r--r-- | src/mobile/MobileMain.tsx | 25 | ||||
-rw-r--r-- | src/mobile/MobileMenu.scss | 402 | ||||
-rw-r--r-- | webpack.config.js | 64 |
18 files changed, 2876 insertions, 339 deletions
diff --git a/deploy/mobile/image.html b/deploy/mobile/image.html index 6424d2a60..d30ad6ac2 100644 --- a/deploy/mobile/image.html +++ b/deploy/mobile/image.html @@ -1,15 +1,14 @@ <html> <head> - <title>Test view</title> + <title>Dash Mobile</title> <link href="https://fonts.googleapis.com/css?family=Fjalla+One|Hind+Siliguri:300" rel="stylesheet"> </head> <body> <div id="root"> - <p>Capture Image: <input type="file" accept="image/*" id="capture"> </div> - <script src="../imageUpload.js"></script> + <script src="../mobileInterface.js"></script> </body> </html>
\ No newline at end of file diff --git a/package-lock.json b/package-lock.json index c956fd3e9..585c0aa1e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2832,7 +2832,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2850,11 +2851,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2867,15 +2870,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2978,7 +2984,8 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2988,6 +2995,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3000,17 +3008,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.9.0", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3027,6 +3038,7 @@ "mkdirp": { "version": "0.5.3", "bundled": true, + "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3082,7 +3094,8 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "npm-packlist": { "version": "1.4.8", @@ -3107,7 +3120,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3117,6 +3131,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3185,7 +3200,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3215,6 +3231,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3232,6 +3249,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3270,11 +3288,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.1.1", - "bundled": true + "bundled": true, + "optional": true } } } @@ -9496,7 +9516,7 @@ }, "chownr": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "resolved": false, "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "ci-info": { @@ -9802,7 +9822,7 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "defaults": { @@ -10301,7 +10321,7 @@ }, "glob": { "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "resolved": false, "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", @@ -10389,7 +10409,7 @@ }, "hosted-git-info": { "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "resolved": false, "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, "http-cache-semantics": { @@ -10525,7 +10545,7 @@ }, "is-ci": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "resolved": false, "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "requires": { "ci-info": "^1.5.0" @@ -10601,7 +10621,7 @@ }, "is-retry-allowed": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "resolved": false, "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" }, "is-stream": { @@ -11110,7 +11130,7 @@ }, "mkdirp": { "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "resolved": false, "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", "requires": { "minimist": "^1.2.5" @@ -11118,7 +11138,7 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "resolved": false, "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } @@ -11170,7 +11190,7 @@ }, "node-gyp": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", + "resolved": false, "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", "requires": { "env-paths": "^2.2.0", @@ -11284,7 +11304,7 @@ }, "npm-packlist": { "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "resolved": false, "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "requires": { "ignore-walk": "^3.0.1", @@ -11304,7 +11324,7 @@ }, "npm-profile": { "version": "4.0.4", - "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", + "resolved": false, "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", "requires": { "aproba": "^1.1.2 || 2", @@ -11314,7 +11334,7 @@ }, "npm-registry-fetch": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz", + "resolved": false, "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==", "requires": { "JSONStream": "^1.3.4", @@ -11749,7 +11769,7 @@ }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { "deep-extend": "^0.6.0", @@ -11760,7 +11780,7 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "resolved": false, "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } @@ -11819,7 +11839,7 @@ }, "readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "resolved": false, "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", @@ -11840,7 +11860,7 @@ }, "registry-auth-token": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "resolved": false, "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "requires": { "rc": "^1.1.6", @@ -11904,7 +11924,7 @@ }, "rimraf": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "resolved": false, "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" @@ -12203,7 +12223,7 @@ }, "string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "resolved": false, "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { "safe-buffer": "~5.2.0" @@ -12211,7 +12231,7 @@ "dependencies": { "safe-buffer": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "resolved": false, "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } @@ -12523,7 +12543,7 @@ }, "widest-line": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "resolved": false, "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "requires": { "string-width": "^2.1.1" diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b0cea9947..1b0622f6d 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -31,6 +31,7 @@ export class CurrentUserUtils { public static get MainDocId() { return this.mainDocId; } public static set MainDocId(id: string | undefined) { this.mainDocId = id; } @computed public static get UserDocument() { return Doc.UserDoc(); } + @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; } @observable public static GuestTarget: Doc | undefined; @observable public static GuestWorkspace: Doc | undefined; @@ -118,6 +119,16 @@ export class CurrentUserUtils { }); } + // if (doc["mobile-button"] === undefined) { + // const mobileTemplate = this.mobileButton({ title: "mobile button", _backgroundColor: "lightgrey" }, [this.ficon({ ignoreClick: true, icon: "mobile", backgroundColor: "rgba(0,0,0,0)" }), this.mobileTextContainer({}, [this.mobileButtonText({}, "text"), this.mobileButtonInfo({}, "This is a default mobile button for use in the mobile menu")])]); + // mobileTemplate.isTemplateDoc = makeTemplate(mobileTemplate); + // doc["mobile-button"] = CurrentUserUtils.ficon({ + // onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + // dragFactory: new PrefetchProxy(mobileTemplate) as any as Doc, + // removeDropProperties: new List<string>(["dropAction"]), title: "mobile button view", icon: "mobile" + // }); + // } + if (doc["template-button-detail"] === undefined) { const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create; @@ -317,6 +328,9 @@ export class CurrentUserUtils { if (doc.emptyWebpage === undefined) { doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _nativeWidth: 850, _nativeHeight: 962, _width: 600, UseCors: true }); } + if (doc.activeMobile === undefined) { + doc.activeMobile = CurrentUserUtils.setupMobileMenu(); + } return [ { title: "Drag a comparison box", label: "Comp", icon: "columns", ignoreClick: true, drag: 'Docs.Create.ComparisonDocument()' }, { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, @@ -330,7 +344,7 @@ export class CurrentUserUtils { { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, - { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, + { title: "Drag a mobile view", label: "Phone", icon: "mobile", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.activeMobile as Doc }, { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' }, // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, @@ -384,25 +398,54 @@ export class CurrentUserUtils { return doc.myItemCreators as Doc; } - static setupMobileButtons(doc: Doc, buttons?: string[]) { - const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "record", icon: "microphone", ignoreClick: true, click: "FILL" }, - { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, - { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, - { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activeInkPen = sameDocs(this.activeInkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "pink", activeInkPen: doc }, - { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activeInkPen = this;', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "white", activeInkPen: doc }, - // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activeInkPen, this)`, backgroundColor: "red", activeInkPen: doc }, - { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" }, - // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, + // static setupActiveMobile(doc: Doc) { + // if (doc.activeMobile === undefined) { + // doc.activeMobile = CurrentUserUtils.setupMobileMenu(); + // } + // } + + static setupMobileMenu() { + const menu = Cast(Docs.Create.StackingDocument(CurrentUserUtils.setupMobileButtons(), { + _width: 980, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "home", _yMargin: 100 + }), Doc) as Doc; + return menu; + } + + 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: "RECORD", icon: "microphone", click: 'openMobileAudio()', backgroundColor: "#ffbfbf", info: "Use your mobile to record audio and access it on Dash Web." }, + { title: "UPLOAD", icon: "upload", click: 'uploadImageMobile()', backgroundColor: "#ff9e9e", info: "Upload an image from your mobile device so it can be accessed on Dash Web" }, + { title: "PRESENTATION", icon: "desktop", click: 'openMobilePresentation()', backgroundColor: "#ff8080", info: "Use your phone as a remote for you presentation." }, + { title: "SETTINGS", icon: "cog", click: 'openMobileSettings()', backgroundColor: "#ff5e5e", info: "Change your password, log out, or manage your account security" } ]; - return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick, - onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, - ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activeInkPen: data.activeInkPen, - backgroundColor: data.backgroundColor, removeDropProperties: new List<string>(["dropAction"]), dragFactory: data.dragFactory, - })); + return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => this.mobileButton({ title: data.title, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, _backgroundColor: data.backgroundColor }, [this.ficon({ ignoreClick: true, icon: data.icon, backgroundColor: "rgba(0,0,0,0)" }), this.mobileTextContainer({}, [this.mobileButtonText({}, data.title), this.mobileButtonInfo({}, data.info)])])); } + static mobileButton = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.MulticolumnDocument(docs, { + ...opts, + dropAction: undefined, removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 900, _nativeHeight: 250, _width: 900, _height: 250, _yMargin: 15, + borderRounding: "5px", boxShadow: "0 0", _chromeStatus: "disabled", + })) as any as Doc + + static mobileTextContainer = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.MultirowDocument(docs, { + ...opts, + dropAction: undefined, removeDropProperties: new List<string>(["dropAction"]), _nativeWidth: 450, _nativeHeight: 250, _width: 450, _height: 250, _yMargin: 25, + backgroundColor: "rgba(0,0,0,0)", borderRounding: "0", boxShadow: "0 0", _chromeStatus: "disabled", ignoreClick: true + })) as any as Doc + + + static mobileButtonText = (opts: DocumentOptions, buttonTitle: string) => new PrefetchProxy(Docs.Create.TextDocument(buttonTitle, { + ...opts, + dropAction: undefined, title: buttonTitle, _fontSize: 37, _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)" + })) as any as Doc + + static mobileButtonInfo = (opts: DocumentOptions, buttonInfo: string) => new PrefetchProxy(Docs.Create.TextDocument(buttonInfo, { + ...opts, + dropAction: undefined, title: "info", _fontSize: 25, _xMargin: 0, _yMargin: 0, ignoreClick: true, _chromeStatus: "disabled", backgroundColor: "rgba(0,0,0,0)", _dimMagnitude: 2, + })) as any as Doc + + static setupThumbButtons(doc: Doc) { const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activeInkPen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activeInkPen, this)`, activeInkPen: doc }, @@ -436,10 +479,8 @@ export class CurrentUserUtils { return Cast(userDoc.thumbDoc, Doc); } - static setupMobileDoc(userDoc: Doc) { - return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), { - columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5 - }); + static setupLibrary(userDoc: Doc) { + return CurrentUserUtils.setupWorkspaces(userDoc); } static setupMobileInkingDoc(userDoc: Doc) { @@ -459,8 +500,8 @@ export class CurrentUserUtils { }); } - // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. - // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) + // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. + // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) { // setup a masonry view of all he creators const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc); @@ -551,7 +592,7 @@ export class CurrentUserUtils { return doc["tabs-button-library"] as Doc; } - // setup the Search button which will display the search panel. + // setup the Search button which will display the search panel. static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) { if (doc["tabs-button-search"] === undefined) { doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({ @@ -643,10 +684,11 @@ export class CurrentUserUtils { static setupRightSidebar(doc: Doc) { if (doc.rightSidebarCollection === undefined) { - doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" })); + doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Mobile Uploads" })); } } + static setupClickEditorTemplates(doc: Doc) { if (doc["clickFuncs-child"] === undefined) { const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( @@ -692,13 +734,14 @@ export class CurrentUserUtils { doc.activeInkWidth = StrCast(doc.activeInkWidth, "1"); doc.activeInkBezier = StrCast(doc.activeInkBezier, ""); doc.fontSize = NumCast(doc.fontSize, 12); - doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // - doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // + doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // + doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon this.setupDocTemplates(doc); // sets up the template menu of templates this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing - this.setupOverlays(doc); // documents in overlay layer + // this.setupActiveMobile(doc); + this.setupOverlays(doc); // documents in overlay layer this.setupDockedButtons(doc); // the bottom bar of font icons this.setupDefaultPresentation(doc); // presentation that's initially triggered await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels @@ -737,4 +780,4 @@ export class CurrentUserUtils { Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); }); Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); }); -Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); });
\ No newline at end of file +Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); diff --git a/src/client/util/SettingsManager.scss b/src/client/util/SettingsManager.scss index 6513cb223..1eac9303b 100644 --- a/src/client/util/SettingsManager.scss +++ b/src/client/util/SettingsManager.scss @@ -133,4 +133,35 @@ } +} + +@media only screen and (max-width: 1000px) { + .settings-interface { + background-color: whitesmoke !important; + color: grey; + width: 80vw; + height: 400px; + } + + .settings-interface .settings-body .settings-content input { + border-radius: 5px; + border: none; + font-size: 30; + padding: 4px; + min-width: 100%; + margin: 2px 0; + } + + .settings-interface button { + width: 100%; + font-size: 30px; + align-self: center; + background: #b2cef8; + margin-top: 4px; + } + + .settings-interface .settings-heading { + letter-spacing: .5em; + font-size: 25; + } }
\ No newline at end of file diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index d239a1d6f..1879f3096 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -5,7 +5,6 @@ import { Doc } from "../../fields/Doc"; import { InkData, InkTool } from "../../fields/InkField"; import { Cast, FieldValue, NumCast } from "../../fields/Types"; import MobileInkOverlay from "../../mobile/MobileInkOverlay"; -import MobileInterface from "../../mobile/MobileInterface"; import { GestureUtils } from "../../pen-gestures/GestureUtils"; import { MobileInkOverlayContent } from "../../server/Message"; import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from "../../Utils"; @@ -24,6 +23,7 @@ import { RadialMenu } from "./nodes/RadialMenu"; import HorizontalPalette from "./Palette"; import { Touchable } from "./Touchable"; import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableMenu"; +import { MobileInterface } from "../../mobile/MobileInterface"; @observer export default class GestureOverlay extends Touchable { diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 203c51163..714ff46a9 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -33,8 +33,9 @@ .collectionStackingViewFieldColumn { height: max-content; } + .collectionStackingViewFieldColumnDragging { - height:100%; + height: 100%; } .collectionSchemaView-previewDoc { @@ -421,4 +422,17 @@ .rc-switch-checked .rc-switch-inner { left: 8px; } +} + +@media only screen and (max-width: 1000px) { + + .collectionStackingView .collectionStackingView-columnDragger, + .collectionMasonryView .collectionStackingView-columnDragger { + width: 30; + transform: translate(0, -40px); + height: 30; + font-size: 40; + position: absolute; + margin-left: -5; + } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 678ad2a53..aee158a2a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -595,7 +595,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => { // bcz: theres should be a better way of doing these than referencing these static instances directly MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2 - PDFMenu.Instance.fadeOut(true); + // PDFMenu.Instance.fadeOut(true); const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true); diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index d48000e16..2bb249ee4 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -16,6 +16,7 @@ height: calc(100% - 25px); width: 100%; } + .presBox-buttons { width: 100%; background: gray; @@ -24,6 +25,7 @@ display: grid; grid-column-end: 4; grid-column-start: 1; + .presBox-viewPicker { height: 25; position: relative; @@ -31,10 +33,12 @@ grid-column: 1/2; min-width: 15px; } + select { background: #323232; color: white; } + .presBox-button { margin-right: 2.5%; margin-left: 2.5%; @@ -44,10 +48,12 @@ align-items: center; background: #323232; color: white; + svg { margin: auto; } } + .collectionViewBaseChrome-viewPicker { min-width: 50; width: 5%; @@ -56,17 +62,68 @@ display: inline-block; } } - .presBox-backward, .presBox-forward { + + .presBox-backward, + .presBox-forward { width: 25px; border-radius: 5px; - top:50%; + top: 50%; position: absolute; display: inline-block; } + .presBox-backward { - left:5; + left: 5; } + .presBox-forward { - right:5; + right: 5; + } +} + +@media only screen and (max-width: 1000px) { + .presBox-cont .presBox-buttons { + position: absolute; + top: 70%; + left: 50%; + transform: translate(-50%, 0); + width: max-content; + height: 15%; + z-index: 2; + align-items: center; + background: rgba(0, 0, 0, 0); + padding-top: 5px; + padding-bottom: 5px; + display: inline-flex; + } + + .presBox-cont .presBox-listCont { + position: absolute; + top: 50; + height: calc(100% - 80px); + width: 100%; + } + + .presBox-cont .presBox-buttons .presBox-button { + margin-right: 10px; + margin-left: 10px; + height: 250; + width: 250; + font-size: 70; + border-radius: 25px; + display: flex; + align-items: center; + background: #323232; + color: white; + } + + .presBox-cont .presBox-buttons .presBox-viewPicker { + top: -70; + left: 2.5%; + height: 50; + width: 95%; + font-size: 30px; + position: absolute; + min-width: 50px; } }
\ No newline at end of file diff --git a/src/client/views/presentationview/PresElementBox.scss b/src/client/views/presentationview/PresElementBox.scss index ccd2e8947..ec82b0c51 100644 --- a/src/client/views/presentationview/PresElementBox.scss +++ b/src/client/views/presentationview/PresElementBox.scss @@ -13,9 +13,10 @@ -moz-user-select: none; -ms-user-select: none; user-select: none; - transition: all .1s; + transition: all .1s; padding: 0px; padding-bottom: 3px; + .documentView-node { position: absolute; z-index: 1; @@ -45,7 +46,7 @@ .presElementBox-closeIcon { border-radius: 20px; - transform:scale(0.7); + transform: scale(0.7); position: absolute; right: 0; top: 0; @@ -58,6 +59,7 @@ position: relative; width: 100%; height: auto; + .presElementBox-interaction { color: gray; float: left; @@ -65,6 +67,7 @@ width: 20px; height: 20px; } + .presElementBox-interaction-selected { color: white; float: left; @@ -90,15 +93,93 @@ display: flex; width: auto; justify-content: center; - margin:auto; + margin: auto; } .presElementBox-embeddedMask { - width:100%; - height:100%; + width: 100%; + height: 100%; position: absolute; - left:0; - top:0; + left: 0; + top: 0; background: transparent; - z-index:2; + z-index: 2; +} + +@media only screen and (max-width: 1000px) { + .presElementBox-buttons { + display: inline-flex; + position: relative; + width: 100%; + } + + .presElementBox-item { + display: inline-flex; + } + + .presElementBox-buttons .presElementBox-interaction { + color: gray; + float: left; + padding: 0px; + width: 50; + height: 50; + } + + .presElementBox-buttons .presElementBox-interaction-selected { + color: white; + float: left; + padding: 0px; + width: 50; + height: 50; + border: solid 1px darkgray; + } + + .presElementBox-closeIcon { + border-radius: 20px; + transform: scale(1.5); + position: absolute; + right: 10; + top: 10; + padding: 8px; + } + + .presElementBox-buttons { + display: inline-flex; + position: absolute; + top: 0; + right: 0; + width: 50%; + } + + .presElementBox-name { + font-size: 30px; + position: absolute; + display: inline-block; + top: 10px; + width: 50%; + text-overflow: ellipsis; + overflow: hidden; + white-space: pre; + } + + .presElementBox-item { + display: inline-block; + background-color: #eeeeee; + pointer-events: all; + width: 100%; + min-height: 100%; + height: max-content; + outline-color: maroon; + outline-style: dashed; + border-radius: 6px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + transition: all .1s; + padding: 0px; + padding-bottom: 3px; + } }
\ No newline at end of file diff --git a/src/mobile/ImageUpload.scss b/src/mobile/ImageUpload.scss index eea69b81c..6c782d4d8 100644 --- a/src/mobile/ImageUpload.scss +++ b/src/mobile/ImageUpload.scss @@ -5,8 +5,21 @@ justify-content: center; flex-direction: column; align-items: center; - width: 100vw; - height: 100vh; + + .upload_label { + font-size: 3em; + font-weight: 700; + color: white; + background-color: black; + display: inline-block; + margin: 10; + width: 100%; + border-radius: 10px; + } + + .upload_label:hover { + background-color: darkred; + } .button_file { text-align: center; @@ -17,18 +30,92 @@ font-size: 3em; } - .input_file { - display: none; + .inputfile { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; } - .upload_label, - .upload_button { - background: $dark-color; - font-size: 500%; - font-family: $sans-serif; - text-align: center; - padding: 5vh; - margin-bottom: 20px; + .inputfile+label { + font-size: 3em; + font-weight: 700; color: white; + background-color: black; + display: inline-block; + margin: 10px; + width: 100%; + border-radius: 10px; + } + + .inputfile:focus+label, + .inputfile+label:hover { + background-color: darkred; } + +} + +.backgroundUpload { + height: 100vh; + top: 0; + z-index: 999; + width: 100vw; + position: absolute; + background-color: lightgrey; + opacity: 0.4; +} + +.image-upload { + top: 100%; + opacity: 0; +} + +.image-upload.active { + top: 0; + position: absolute; + z-index: 999; + height: 100vh; + width: 100vw; + opacity: 1; +} + +.uploadContainer { + top: 40; + position: absolute; + z-index: 1000; + height: 20vh; + width: 80vw; + opacity: 1; +} + +.closeUpload { + position: absolute; + border-radius: 10px; + top: 39.7%; + color: grey; + font-size: 40; + left: 65.8%; + z-index: 1002; + padding: 0px 3px; + background: aliceblue; + transition: 0.5s ease all; + border: 3px solid; + border-color: black; +} + +.loadingImage { + display: inline-flex; + width: max-content; +} + +.loadingSlab { + position: relative; + width: 30px; + height: 30px; + margin: 10; + border-radius: 20px; + opacity: 0.3; + background-color: black; }
\ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index b15042f9f..504e4ceae 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -4,16 +4,20 @@ import { Docs } from '../client/documents/Documents'; import "./ImageUpload.scss"; import React = require('react'); import { DocServer } from '../client/DocServer'; -import { Opt, Doc } from '../fields/Doc'; +import { observer } from 'mobx-react'; +import { observable, action } from 'mobx'; +import { Utils } 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 { observer } from 'mobx-react'; -import { observable } from 'mobx'; -import { Utils } from '../Utils'; -import MobileInterface from './MobileInterface'; -import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; -import { resolvedPorts } from '../client/views/Main'; +import { Scripting } from '../client/util/Scripting'; +import MainViewModal from '../client/views/MainViewModal'; + +export interface ImageUploadProps { + Document: Doc; +} // const onPointerDown = (e: React.TouchEvent) => { // let imgInput = document.getElementById("input_image_file"); @@ -24,39 +28,56 @@ import { resolvedPorts } from '../client/views/Main'; const inputRef = React.createRef<HTMLInputElement>(); @observer -class Uploader extends React.Component { +export class Uploader extends React.Component { @observable error: string = ""; @observable status: string = ""; + @observable nm: string = "Choose an image"; onClick = async () => { console.log("uploader click"); try { this.status = "initializing protos"; + const slab1 = document.getElementById("slab1"); + if (slab1) { + slab1.style.opacity = "1"; + } await Docs.Prototypes.initialize(); const imgPrev = document.getElementById("img_preview"); + console.log("buddy"); if (imgPrev) { + console.log("hi"); const files: FileList | null = inputRef.current!.files; if (files && files.length !== 0) { console.log(files[0]); const name = files[0].name; - const formData = new FormData(); - formData.append("file", files[0]); - - const upload = window.location.origin + "/uploadFormData"; + const res = await Networking.UploadFilesToServer(files[0]); this.status = "uploading image"; - console.log("uploading image", formData); - const res = await fetch(upload, { - method: 'POST', - body: formData - }); + const slab2 = document.getElementById("slab2"); + if (slab2) { + slab2.style.opacity = "1"; + } this.status = "upload image, getting json"; - const json = await res.json(); - json.map(async (file: any) => { - const path = window.location.origin + file; + const slab3 = document.getElementById("slab3"); + if (slab3) { + slab3.style.opacity = "1"; + } + res.map(async ({ result }) => { + if (result instanceof Error) { + return; + } + const path = Utils.prepend(result.accessPaths.agnostic.client); const doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name }); this.status = "getting user document"; - + const slab4 = document.getElementById("slab4"); + if (slab4) { + slab4.style.opacity = "1"; + } + this.status = "upload image, getting json"; + const slab5 = document.getElementById("slab5"); + if (slab5) { + slab5.style.opacity = "1"; + } const res = await rp.get(Utils.prepend("/getUserDocumentId")); if (!res) { throw new Error("No user id returned"); @@ -68,6 +89,10 @@ class Uploader extends React.Component { } if (pending) { this.status = "has pending docs"; + const slab6 = document.getElementById("slab6"); + if (slab6) { + slab6.style.opacity = "1"; + } const data = await Cast(pending.data, listSpec(Doc)); if (data) { data.push(doc); @@ -75,54 +100,113 @@ class Uploader extends React.Component { pending.data = new List([doc]); } this.status = "finished"; - } - }); + console.log("hi"); + const slab7 = document.getElementById("slab7"); + if (slab7) { + slab7.style.opacity = "1"; + } - // console.log(window.location.origin + file[0]) + } - //imgPrev.setAttribute("src", window.location.origin + files[0].name) + }); } + setTimeout(this.clearUpload, 3000); } } catch (error) { this.error = JSON.stringify(error); } + } - render() { + // 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 !== 0) { + console.log(files); + this.nm = files[0].name; + } + } + + @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 an image"; + + if (inputRef.current) { + inputRef.current.value = ""; + } + console.log(inputRef.current!.files); + } + + + + private get uploadInterface() { return ( <div className="imgupload_cont"> - <label htmlFor="input_image_file" className="upload_label">Choose an Image</label> - <input type="file" accept="image/*" className="input_file" id="input_image_file" ref={inputRef}></input> - <button onClick={this.onClick} className="upload_button">Upload</button> + <input type="file" accept="image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel}></input> + <label id="label" htmlFor="input_image_file">{this.nm}</label> + <div className="upload_label" onClick={this.onClick}>Upload Image</div> + {/* <div onClick={this.onClick} className="upload_button">Upload</div> */} <img id="img_preview" src=""></img> - <p>{this.status}</p> - <p>{this.error}</p> + {/* <p>{this.status}</p> + <p>{this.error}</p> */} + <div className="loadingImage"> + <div className="loadingSlab" id="slab1" /> + <div className="loadingSlab" id="slab2" /> + <div className="loadingSlab" id="slab3" /> + <div className="loadingSlab" id="slab4" /> + <div className="loadingSlab" id="slab5" /> + <div className="loadingSlab" id="slab6" /> + <div className="loadingSlab" id="slab7" /> + </div> </div> ); } -} - + @observable private dialogueBoxOpacity = 1; + @observable private overlayOpacity = 0.4; -// DocServer.init(window.location.protocol, window.location.hostname, resolvedPorts.socket, "image upload"); -(async () => { - const info = await CurrentUserUtils.loadCurrentUser(); - DocServer.init(window.location.protocol, window.location.hostname, resolvedPorts.socket, info.email + "mobile"); - await Docs.Prototypes.initialize(); - if (info.id !== "__guest__") { - // a guest will not have an id registered - await CurrentUserUtils.loadUserDocument(info); + render() { + return ( + <MainViewModal + contents={this.uploadInterface} + isDisplayed={true} + interactive={true} + dialogueBoxDisplayedOpacity={this.dialogueBoxOpacity} + overlayDisplayedOpacity={this.overlayOpacity} + /> + ); } - document.getElementById('root')!.addEventListener('wheel', event => { - if (event.ctrlKey) { - event.preventDefault(); - } - }, true); - ReactDOM.render(( - // <Uploader /> - <MobileInterface /> - ), - document.getElementById('root') - ); + } -)();
\ No newline at end of file + + +// DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload"); diff --git a/src/mobile/MobileHome.scss b/src/mobile/MobileHome.scss new file mode 100644 index 000000000..e1566b622 --- /dev/null +++ b/src/mobile/MobileHome.scss @@ -0,0 +1,101 @@ +$navbar-height: 120px; +$pathbar-height: 50px; + +* { + margin: 0px; + padding: 0px; + box-sizing: border-box; + font-family: "Open Sans"; +} + +.homeContainer { + position: relative; + top: 200px; + overflow: scroll; + width: 100%; + left: 0; + height: calc(100% - 120px); + overflow-y: scroll; +} + +.homeButton { + width: 96%; + margin-left: 2.5%; + height: 250px; + border-radius: 30px; + margin-top: 15px; + margin-bottom: 15px; +} + +.iconRight { + position: absolute; + width: 50%; + height: 80px; + transform: translate(0, 50%); + right: 0px; + text-align: center; + font-size: 80; +} + +.iconLeft { + position: absolute; + width: 50%; + height: 80px; + transform: translate(0%, 50%); + left: 0px; + text-align: center; + font-size: 80; +} + +.textLeft { + position: absolute; + width: 50%; + left: 0px; + font-size: 40px; + text-align: left; + margin-left: 110px; + margin-top: 40px; + font-family: sans-serif; + font-weight: bold; +} + +.textRight { + position: absolute; + width: 50%; + right: 0px; + font-size: 40px; + text-align: right; + margin-right: 110px; + margin-top: 40px; + font-family: sans-serif; + font-weight: bold; +} + +.menuView { + position: absolute; + top: 135px; + left: 50%; + transform: translate(-50%, 0%); + display: flex; +} + +.iconView { + height: 60px; + width: 60px; + background-color: darkgray; + border-radius: 5px; + border-style: solid; + border-width: 2px; + border-color: black; +} + +.listView { + height: 60px; + width: 60px; + margin-left: 20; + background-color: darkgray; + border-radius: 5px; + border-style: solid; + border-width: 2px; + border-color: black; +}
\ No newline at end of file diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 973931615..1b3388161 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -4,11 +4,9 @@ import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPosition import { observable, action } from "mobx"; import { GestureUtils } from "../pen-gestures/GestureUtils"; import "./MobileInkOverlay.scss"; -import { StrCast, Cast } from '../fields/Types'; import { DragManager } from "../client/util/DragManager"; import { DocServer } from '../client/DocServer'; -import { Doc, DocListCastAsync } from '../fields/Doc'; -import { listSpec } from '../fields/Schema'; +import { Doc } from '../fields/Doc'; @observer diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss index 4d86e208f..f75e60a37 100644 --- a/src/mobile/MobileInterface.scss +++ b/src/mobile/MobileInterface.scss @@ -16,4 +16,13 @@ height: 100%; position: relative; touch-action: none; + width: 100%; +} + +.mobileInterface-background { + height: 100%; + width: 100%; + position: relative; + touch-action: none; + background-color: pink; }
\ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index da14ffc88..d9399d549 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -1,47 +1,979 @@ -import React = require('react'); +import * as React from "react"; import { library } from '@fortawesome/fontawesome-svg-core'; -import { faEraser, faHighlighter, faLongArrowAltLeft, faMousePointer, faPenNib } from '@fortawesome/free-solid-svg-icons'; +import { + faTasks, 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, + faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, + faThumbtack, faTree, faTv, faBook, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft +} 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 { DocumentManager } from '../client/util/DocumentManager'; -import RichTextMenu from '../client/views/nodes/formattedText/RichTextMenu'; import { Scripting } from '../client/util/Scripting'; -import { Transform } from '../client/util/Transform'; -import { DocumentDecorations } from '../client/views/DocumentDecorations'; -import GestureOverlay from '../client/views/GestureOverlay'; import { DocumentView } from '../client/views/nodes/DocumentView'; -import { RadialMenu } from '../client/views/nodes/RadialMenu'; -import { PreviewCursor } from '../client/views/PreviewCursor'; -import { Doc, DocListCast, FieldResult } from '../fields/Doc'; -import { Id } from '../fields/FieldSymbols'; +import { Transform } from '../client/util/Transform'; +// import { InkingControl } from '../client/views/InkingControl'; +import "./MobileInterface.scss"; +import "./MobileMenu.scss"; +import "./MobileHome.scss"; +import "./ImageUpload.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 { Cast, FieldValue } from '../fields/Types'; -import { WebField } from "../fields/URLField"; -import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; -import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; -import "./MobileInterface.scss"; -import { CollectionView } from '../client/views/collections/CollectionView'; -import { InkingStroke } from '../client/views/InkingStroke'; +import { nullAudio, WebField } from '../fields/URLField'; +import GestureOverlay from "../client/views/GestureOverlay"; +import { SelectionManager } from "../client/util/SelectionManager"; +import { SketchPicker } from "react-color"; +import { ScriptField } from "../fields/ScriptField"; + +library.add(faTasks, 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, + faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, + faThumbtack, faTree, faTv, faUndoAlt, faBook, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faHome, faLongArrowAltLeft, faBars, faTh, faChevronLeft); + +// @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; +// public _homeDoc: Doc = this.mainDoc; +// private _homeMenu: boolean = true; + +// // private inkDoc?: Doc; +// public drawingInk: boolean = false; +// private _ink: boolean = false; + +// // private _uploadDoc: Doc = this.userDoc; +// private _child: Doc | null = null; +// private _parents: Array<Doc> = []; +// private _library: Doc = CurrentUserUtils.setupLibrary(this.userDoc); +// private _open: boolean = false; + +// 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._homeDoc; +// } + +// InkingControl.Instance.switchTool(InkTool.None); +// MobileInterface.Instance.drawingInk = false; +// InkingControl.Instance.updateSelectedColor("#FF0000"); +// InkingControl.Instance.switchWidth("2"); +// this.switchCurrentView((userDoc: Doc) => this._homeDoc); +// } + +// @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 = () => { +// const button = document.getElementById("inkButton") as HTMLElement; +// const color = InkingControl.Instance.selectedColor; +// button.style.backgroundColor = this._ink ? "white" : color; +// button.style.color = this._ink ? "black" : "white"; + +// if (!this._ink) { +// console.log("INK IS ACTIVE"); +// InkingControl.Instance.switchTool(InkTool.Pen); +// MobileInterface.Instance.drawingInk = true; +// this._ink = true; +// } else { +// console.log("INK IS INACTIVE"); +// InkingControl.Instance.switchTool(InkTool.None); +// MobileInterface.Instance.drawingInk = false; +// this._ink = false; +// } +// } + +// 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 = () => { +// let header = document.getElementById("header") as HTMLElement; +// let doc = Cast(this._parents.pop(), Doc) as Doc; +// if (doc === Cast(this._library, Doc) as Doc) { +// this._child = null; +// this.userDoc.activeMobile = this._library; +// } else if (doc === Cast(this._homeDoc, Doc) as Doc) { +// this._homeMenu = true; +// this._parents = []; +// this._activeDoc = this._homeDoc; +// this._child = null; +// this.switchCurrentView((userDoc: Doc) => this._homeDoc); +// } else { +// if (doc) { +// this._child = doc; +// this.switchCurrentView((userDoc: Doc) => doc); +// this._homeMenu = false; +// header.textContent = String(doc.title); +// } +// } +// if (doc) { +// this._activeDoc = doc; +// } +// this._ink = false; +// } + +// returnHome = () => { +// if (this._homeMenu === false || this._open === true) { +// this._homeMenu = true; +// this._parents = []; +// this._activeDoc = this._homeDoc; +// this._child = null; +// this.switchCurrentView((userDoc: Doc) => this._homeDoc); +// } +// if (this._open) { +// this.toggleSidebar(); +// } +// } + +// returnMain = () => { +// this._parents = []; +// // this.toggleSidebar(); +// this._activeDoc = this._library; +// this.switchCurrentView((userDoc: Doc) => this._library); +// this._homeMenu = false; +// this._child = null; +// } + +// displayWorkspaces = () => { +// if (this.mainContainer) { +// const backgroundColor = () => "white"; +// if (this._activeDoc.title === "mobile audio") { +// return ( +// <div style={{ position: "relative", top: '600px', height: `calc(50% - 450px)`, width: "80%", overflow: "hidden", left: "10%", cursor: "pointer" }}> +// <DocumentView +// Document={this.mainContainer} +// DataDoc={undefined} +// LibraryPath={emptyPath} +// addDocument={returnFalse} +// addDocTab={returnFalse} +// pinToPres={emptyFunction} +// rootSelected={returnFalse} +// removeDocument={undefined} +// onClick={undefined} +// ScreenToLocalTransform={Transform.Identity} +// ContentScaling={returnOne} +// NativeHeight={returnZero} +// NativeWidth={returnZero} +// PanelWidth={() => window.screen.width} +// PanelHeight={() => window.screen.height} +// renderDepth={0} +// focus={emptyFunction} +// backgroundColor={backgroundColor} +// parentActive={returnTrue} +// whenActiveChanged={emptyFunction} +// bringToFront={emptyFunction} +// ContainingCollectionView={undefined} +// ContainingCollectionDoc={undefined} +// /> +// </div> +// ); +// } else { +// return ( +// <div style={{ position: "relative", top: '200px', height: `calc(100% - 200px)`, width: "100%", overflow: "hidden", left: "0%" }}> +// <DocumentView +// Document={this.mainContainer} +// DataDoc={undefined} +// LibraryPath={emptyPath} +// addDocument={returnFalse} +// addDocTab={returnFalse} +// pinToPres={emptyFunction} +// rootSelected={returnFalse} +// removeDocument={undefined} +// onClick={undefined} +// ScreenToLocalTransform={Transform.Identity} +// ContentScaling={returnOne} +// PanelWidth={this.returnWidth} +// PanelHeight={this.returnHeight} +// NativeHeight={returnZero} +// NativeWidth={returnZero} +// renderDepth={0} +// focus={emptyFunction} +// backgroundColor={backgroundColor} +// parentActive={returnTrue} +// whenActiveChanged={emptyFunction} +// bringToFront={emptyFunction} +// ContainingCollectionView={undefined} +// ContainingCollectionDoc={undefined} +// // mobile={true} +// /> +// </div> +// ); +// } +// } +// } + +// returnWidth = () => 2000; +// returnHeight = () => 2000; + +// handleClick(doc: Doc) { +// let children = DocListCast(doc.data); +// if (doc.type !== "collection") { +// 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"); +// } else { +// this._parents.push(this._activeDoc); +// this._activeDoc = doc; +// this.switchCurrentView((userDoc: Doc) => doc); +// this._homeMenu = false; +// this._child = doc; +// } + +// // let sidebar = document.getElementById("sidebar") as HTMLElement; +// // sidebar.classList.toggle('active'); +// } + +// createPathname = () => { +// let docArray = []; +// this._parents.map((doc: Doc, index: any) => { +// // if (doc === this.mainDoc) { +// // pathname = pathname; +// // } else if (doc.type === "audio" || doc.type === "presentation") { +// // pathname = pathname; +// // } else if (doc.type !== "collection") { +// // pathname = pathname; +// // } else { +// // pathname = pathname + " > " + doc.title; +// // titleArray.push(doc.title); +// // docArray.push(doc); +// // } +// docArray.push(doc); +// }); +// docArray.push(this._activeDoc); +// // if (this._activeDoc.title === "mobile audio") { +// // pathname = this._activeDoc.title; +// // } else if (this._activeDoc.title === "Presentation") { +// // pathname = this._activeDoc.title; +// // } else if (this._activeDoc === this.mainDoc) { +// // pathname = pathname; +// // } else { +// // pathname = pathname + " > " + this._activeDoc.title; +// // docArray.push(this._activeDoc); +// // titleArray.push(this._activeDoc.title); +// // } + +// return docArray; +// } + +// renderPathbar = () => { +// // if (this._homeMenu == false) { +// let docArray = this.createPathname(); +// let items = docArray.map((doc: Doc, index: any) => { +// if (index == 0) { +// return ( +// <div className="pathbarItem"> +// <div className="pathbarText" +// key={index} +// onClick={() => this.handlePathClick(doc, index)}>{doc.title} +// </div> +// </div>); +// } else if (doc === this._activeDoc) { +// return ( +// <div className="pathbarItem"> +// <FontAwesomeIcon className="pathIcon" icon="angle-right" size="lg" /> +// <div className="pathbarText" +// style={{ backgroundColor: "rgb(119, 37, 37)" }} +// key={index} +// onClick={() => this.handlePathClick(doc, index)}>{doc.title} +// </div> +// </div>); +// } else { +// return ( +// <div className="pathbarItem"> +// <FontAwesomeIcon className="pathIcon" icon="angle-right" size="lg" /> +// <div className="pathbarText" +// key={index} +// onClick={() => this.handlePathClick(doc, index)}>{doc.title} +// </div> +// </div>); +// } + +// }); +// if (this._parents.length !== 0) { +// return (<div className="pathbar"> +// <div className="scrollmenu"> +// {items} +// </div> +// <div className="back" > +// <FontAwesomeIcon onClick={this.back} icon={"chevron-left"} color="white" size={"2x"} /> +// </div> +// <div className="hidePath" /> +// </div>); +// } else { +// return (<div className="pathbar"> +// <div className="scrollmenu"> +// {items} +// </div> +// <div className="hidePath" /> +// </div>); +// } +// // } +// // } else { + +// // return ( +// // <div className="pathbar"> +// // <div className="scrollmenu"> +// // <div className="pathbarItem"> +// // <div className="pathbarText" +// // style={{ backgroundColor: "rgb(119, 37, 37)" }} +// // key={0} +// // onClick={() => this.returnHome()}>Home +// // </div> +// // </div> +// // </div> +// // <div className="hidePath" /> +// // </div> +// // ); +// // } + +// // } +// } + +// handlePathClick = (doc: Doc, index: number) => { +// if (doc === this._library) { +// this._activeDoc = doc; +// this._child = null; +// this.switchCurrentView((userDoc: Doc) => doc); +// this._parents.length = index; +// } else if (doc === this._homeDoc) { +// this.returnHome(); +// } else { +// console.log(index); +// this._activeDoc = doc; +// this._child = doc; +// this.switchCurrentView((userDoc: Doc) => doc); +// this._parents.length = index; +// } +// } + +// @action +// toggleSidebar = () => this.sidebarActive = !this.sidebarActive + +// switchToLibrary = () => { +// this._parents.push(this._activeDoc); +// this.switchCurrentView((userDoc: Doc) => this._library); +// this._activeDoc = this._library; +// this._homeMenu = false; +// this.toggleSidebar(); +// } + +// // renderDefaultContent = () => { +// // let menuButtons = DocListCast(this._homeDoc.data).map((doc: Doc, index: any) => { +// // if (doc.type !== "ink") { +// // return ( +// // <div +// // className="item" +// // key={index} +// // onClick={() => doc.click}>{doc.title} +// // </div>); +// // } +// // }); + +// // if (this._homeMenu === true) { +// // return ( +// // <div> +// // <div className="navbar"> +// // <FontAwesomeIcon className="home" icon="home" onClick={this.returnHome} /> +// // <div className="header" id="header">{this._homeDoc.title}</div> +// // <div className="toggle-btn" id="menuButton" onClick={this.toggleSidebar}> +// // <span></span> +// // <span></span> +// // <span></span> +// // </div> +// // </div> +// // {this.renderPathbar()} +// // <div className="sidebar" id="sidebar"> +// // <div className="sidebarButtons"> +// // {menuButtons} +// // </div> +// // </div> +// // </div> +// // ); +// // } + +// // 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 ( +// // <div +// // className="item" +// // key={index} +// // onClick={() => this.handleClick(doc)}>{doc.title} +// // <div className="type">{doc.type}</div> +// // <FontAwesomeIcon className="right" icon="angle-right" size="lg" /> +// // </div>); +// // }); +// // return ( +// // <> +// // <div className="navbar"> +// // <div className={"header"}>{this.sidebarActive ? StrCast(this._activeDoc.title) : "Menu"}</div> +// // <div +// // className={`toggle-btn ${this.sidebarActive ? "active" : ""}`} +// // onClick={this.toggleSidebar} +// // /> +// // </div> +// // <div className="pathbar"> +// // <div className="pathname">{this.createPathname()}</div> +// // </div> +// // <div className={`sidebar ${this.sidebarActive ? "active" : ""}`}> +// // <FontAwesomeIcon className="home" icon="home" onClick={this.returnHome} /> +// // {this._child ? +// // <> +// // <div className="back" onClick={this.back}>←</div> +// // <div>{buttons}</div> +// // <div className="item" key="home" onClick={this.returnHome}>Home</div> +// // </> : +// // <> +// // {buttons} +// // {/* <div className="item" key="library" onClick={this.openLibrary}> +// // Library +// // </div> */} +// // <Uploader Document={workspaces} /> +// // <div className="item" key="audio" onClick={this.recordAudio}>Record Audio</div> +// // <div className="item" key="presentation" onClick={this.setupDefaultPresentation}>Presentation</div> +// // <div className="item" key="settings" onClick={() => SettingsManager.Instance.open()}>Settings</div> +// // </> +// // } +// // </div> +// // {this._child ? null : <div>{this.renderView}</div>} +// // </> +// // ); +// // } + +// recordAudio = async () => { +// // upload to server with known URL +// if (this._activeDoc.title !== "mobile audio") { +// this._parents.push(this._activeDoc); +// } +// const audioDoc = Cast(Docs.Create.AudioDocument(nullAudio, { _width: 200, _height: 100, title: "mobile audio" }), Doc) as Doc; +// console.log(audioDoc); +// if (audioDoc) { +// console.log("audioClicked: " + audioDoc.title); +// this._activeDoc = audioDoc; +// this.switchCurrentView((userDoc: Doc) => audioDoc); +// this._homeMenu = false; +// // this.toggleSidebar(); +// } +// // const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; +// // this.audioState = await audioDoc.getProto; +// // if (this.audioState) { +// // console.log(this.audioState); +// // const data = Cast(audioRightSidebar.data, listSpec(Doc)); +// // if (data) { +// // data.push(audioDoc); +// // } +// // } +// } + +// uploadAudio = () => { +// const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; +// const audioDoc = this._activeDoc; +// const data = Cast(audioRightSidebar.data, listSpec(Doc)); +// console.log(audioDoc.proto); +// if (data) { +// data.push(audioDoc); +// } +// // this.recordAudio(); +// } + +// uploadAudioButton = () => { +// if (this._activeDoc.type === "audio") { +// return <div className="docButton" +// title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} +// style={{ backgroundColor: "black", color: "white" }} +// onClick={this.uploadAudio} +// > +// <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="upload" +// /> +// </div>; +// } +// } + +// toggleSelector = () => { +// console.log("toggle selector!"); +// let toolbar = document.getElementById("toolbar") as HTMLElement; +// toolbar.classList.toggle('active'); +// } + +// colorTool = () => { +// if (this._activeDoc._viewType === "docking") { +// const color = InkingControl.Instance.selectedColor; +// console.log(color); +// return ( +// <div +// className="docButton" +// style={{ backgroundColor: color }} +// onClick={this.toggleSelector} +// > +// <div className="toolbar" id="toolbar"> +// <div className="colorSelector"> +// <div className="colorButton" +// style={{ backgroundColor: "red" }} +// onClick={() => { +// InkingControl.Instance.updateSelectedColor("rgb(255,0,0)"); +// Doc.UserDoc().inkColor = "rgb(255,0,0)"; +// console.log(InkingControl.Instance.selectedColor); +// }}> +// </div> +// <div className="colorButton" +// style={{ backgroundColor: "green" }} +// onClick={e => { +// InkingControl.Instance.updateSelectedColor("rgb(0,128,0)"); +// Doc.UserDoc().inkColor = "rgb(0,128,0)"; +// console.log(InkingControl.Instance.selectedColor); +// }}> +// </div> +// <div className="colorButton" +// style={{ backgroundColor: "blue" }} +// onClick={e => { +// InkingControl.Instance.updateSelectedColor("rgb(0,0,255)"); +// Doc.UserDoc().inkColor = "rgb(0,0,255)"; +// console.log(InkingControl.Instance.selectedColor); +// }}> +// </div> +// </div> +// <div className="widthSelector"> +// <input type="range" min="1" max="100" defaultValue="2" id="myRange" onChange={(e: React.ChangeEvent<HTMLInputElement>) => InkingControl.Instance.switchWidth(e.target.value)} /> +// </div> +// </div> +// </div> +// ); +// } +// } + +// drawInk = () => { +// if (this._activeDoc._viewType === "docking") { +// const inkIsOn = this._ink; +// return <div className="docButton" +// id="inkButton" +// title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} +// onClick={this.onSwitchInking}> +// <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="pen-nib" +// /> +// </div>; +// } +// } + +// downloadDocument = () => { +// if (this._activeDoc.type === "image") { +// const url = this._activeDoc["data-path"]?.toString(); +// return <div className="docButton" +// title={"Download Image"} +// style={{ backgroundColor: "white", color: "black" }} +// onClick={e => { +// window.open(url); +// console.log(url); +// }}> +// <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="download" +// /> +// </div>; +// } +// } + +// pinToPresentation = () => { +// // Only making button available if it is an image +// if (this._activeDoc.type === "image") { +// const isPinned = this._activeDoc && Doc.isDocPinned(this._activeDoc); +// return <div className="docButton" +// title={Doc.isDocPinned(this._activeDoc) ? "Unpin from presentation" : "Pin to presentation"} +// style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }} +// onClick={e => { +// if (isPinned) { +// DockedFrameRenderer.UnpinDoc(this._activeDoc); +// } +// else { +// DockedFrameRenderer.PinDoc(this._activeDoc); +// } +// }}> +// <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" +// /> +// </div>; +// } +// } + +// setupDefaultPresentation = () => { +// if (this._activeDoc.title !== "Presentation") { +// this._parents.push(this._activeDoc); +// } + +// const presentation = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + +// if (presentation) { +// console.log(this._activeDoc.mobile); +// console.log("presentation clicked: " + presentation.title); +// this._activeDoc = presentation; +// this.switchCurrentView((userDoc: Doc) => presentation); +// this._homeMenu = false; +// // this.toggleSidebar(); +// } +// } + +// // mobileHome = () => { +// // return ( +// // <div className="homeContainer"> +// // <div className="uploadButton"> + +// // </div> +// // <div className="presentationButton"> + +// // </div> +// // <div className="recordAudioButton"> + +// // </div> +// // <div className="inkButton"> + +// // </div> +// // <div className="settingsButton"> + +// // </div> +// // </div> +// // ); +// // } + +// renderActiveCollection = (userDoc: Doc) => { +// if (this.activeContainer) { +// const active = Cast(this.activeContainer.data, listSpec(Doc)); +// if (active) { +// return ( +// <div className="mobileInterface-background">HELLO!</div> +// ); +// } +// } +// } + +// 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; +// } -library.add(faLongArrowAltLeft); +// 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<WebField> = 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<Doc>(); +// } +// } +// } + +// 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 ( +// <div className="mobileInterface-container" onDragOver={this.onDragOver}> +// {/* <DocumentDecorations /> +// <GestureOverlay> +// {this.renderView ? this.renderView() : this.renderDefaultContent()} +// </GestureOverlay> */} +// {/* <GestureOverlay> */} +// <SettingsManager /> +// {/* {this.menuOptions()} */} +// {/* {this.displayHome()} */} +// <div className="docButtonContainer"> +// {this.pinToPresentation()} +// {this.downloadDocument()} +// {this.drawInk()} +// {this.uploadAudioButton()} +// {this.colorTool()} +// </div> +// <GestureOverlay> + +// </GestureOverlay> +// {this.renderDefaultContent()} +// {this.displayWorkspaces()} +// {/* </GestureOverlay> */} +// {/* <DictationOverlay /> +// <SharingManager /> +// <GoogleAuthenticationManager /> */} +// {/* <DocumentDecorations /> */} +// {/* <div> +// {this.renderDefaultContent()} +// </div> */} +// {/* <PreviewCursor /> */} +// {/* <ContextMenu /> */} +// {/* <RadialMenu /> +// <RichTextMenu /> */} +// {/* <PDFMenu /> +// <MarqueeOptionsMenu /> +// <OverlayView /> */} +// </div> +// ); +// } +// } + +// 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 openMobileSettings() { return SettingsManager.Instance.open(); }); +// Scripting.addGlobal(function switchToLibrary() { return MobileInterface.Instance.switchToLibrary(); }); +// // WAS 2 + +// // 1 +// // renderUploadContent() { +// // if (this.mainContainer) { +// // return ( +// // <div className="mobileInterface" onDragOver={this.onDragOver}> +// // <div className="mobileInterface-inkInterfaceButtons"> +// // <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button> +// // {/* <button className="mobileInterface-button" onClick={this.clearUpload} title="Clear Upload">CLEAR</button> */} +// // {/* <button className="mobileInterface-button" onClick={this.addWeb} title="Add Web Doc to Upload Collection"></button> */} +// // <button className="mobileInterface-button" onClick={this.upload} title="Upload">UPLOAD</button> +// // </div> +// // <DocumentView +// // Document={this.mainContainer} +// // DataDoc={undefined} +// // LibraryPath={emptyPath} +// // addDocument={returnFalse} +// // addDocTab={returnFalse} +// // pinToPres={emptyFunction} +// // rootSelected={returnFalse} +// // removeDocument={undefined} +// // onClick={undefined} +// // ScreenToLocalTransform={Transform.Identity} +// // ContentScaling={returnOne} +// // NativeHeight={returnZero} +// // NativeWidth={returnZero} +// // PanelWidth={() => window.screen.width} +// // PanelHeight={() => window.screen.height} +// // renderDepth={0} +// // focus={emptyFunction} +// // backgroundColor={returnEmptyString} +// // parentActive={returnTrue} +// // whenActiveChanged={emptyFunction} +// // bringToFront={emptyFunction} +// // ContainingCollectionView={undefined} +// // ContainingCollectionDoc={undefined} /> +// // </div> +// // ); +// // } +// // } + +// // 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 ( +// // <div className="mobileInterface"> +// // <div className="mobileInterface-inkInterfaceButtons"> +// // <div className="navButtons"> +// // <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing">BACK</button> +// // </div> +// // <div className="inkSettingButtons"> +// // <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button> +// // </div> +// // <div className="navButtons"> +// // <button className="mobileInterface-button" onClick={this.shiftLeft} title="Shift left">left</button> +// // <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button> +// // </div> +// // </div> +// // <CollectionView +// // Document={this.mainContainer} +// // DataDoc={undefined} +// // LibraryPath={emptyPath} +// // fieldKey={""} +// // dropAction={"alias"} +// // bringToFront={emptyFunction} +// // addDocTab={returnFalse} +// // pinToPres={emptyFunction} +// // PanelWidth={this.panelWidth} +// // PanelHeight={this.panelHeight} +// // NativeHeight={returnZero} +// // NativeWidth={returnZero} +// // focus={emptyFunction} +// // isSelected={returnFalse} +// // select={emptyFunction} +// // active={returnFalse} +// // ContentScaling={returnOne} +// // whenActiveChanged={returnFalse} +// // ScreenToLocalTransform={Transform.Identity} +// // renderDepth={0} +// // ContainingCollectionView={undefined} +// // ContainingCollectionDoc={undefined} +// // rootSelected={returnTrue}> +// // </CollectionView> +// // </div> +// // ); +// // } +// // } @observer -export default class MobileInterface extends React.Component { +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; } - // @observable private currentView: "main" | "ink" | "upload" = "main"; - private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc); + // @computed private get activeContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } + // Sets up new mobile menu only if activeMobile already exists + // @observable private mainDoc: any = this.userDoc.activeMobile === undefined ? CurrentUserUtils.setupMobileMenu() : this.userDoc.activeMobile; + @observable private mainDoc: any = CurrentUserUtils.setupMobileMenu(); @observable private renderView?: () => JSX.Element; + @observable private audioState: any; + @observable private activeToolbar: boolean = false; + @observable private sidebarActive: boolean = false; + @observable private imageUploadActive: boolean = false; + @observable private menuListView: boolean = false; + + public _activeDoc: Doc = this.mainDoc; + public _homeDoc: Doc = this.mainDoc; + private _homeMenu: boolean = true; // private inkDoc?: Doc; public drawingInk: boolean = false; - // private uploadDoc?: Doc; + // private _uploadDoc: Doc = this.userDoc; + private _child: Doc | null = null; + private _parents: Array<Doc> = []; + private _library: Doc = CurrentUserUtils.setupLibrary(this.userDoc); + private _open: boolean = false; + + // private _library: Doc = Cast(this.userDoc.myWorkspaces, Doc) as Doc; + private _ink: boolean = false; constructor(props: Readonly<{}>) { super(props); @@ -50,37 +982,35 @@ export default class MobileInterface extends React.Component { @action componentDidMount = () => { - library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer]); - + library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer, faThumbtack]); + if (this.userDoc.activeMobile) { + console.log(Doc.UserDoc().activeMobile); + } if (this.userDoc && !this.mainContainer) { - this.userDoc.activeMobile = this.mainDoc; + this.userDoc.activeMobile = this._homeDoc; } + this._homeDoc._viewType === "stacking" ? this.menuListView = true : this.menuListView = false; + // InkingStroke.switchTool(InkTool.None); + MobileInterface.Instance.drawingInk = false; + // InkingControl.Instance.updateSelectedColor("#FF0000"); + // InkingControl.Instance.switchWidth("2"); + this.switchCurrentView((userDoc: Doc) => this._homeDoc); } @action switchCurrentView = (doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) => { if (!this.userDoc) return; - this.userDoc.activeMobile = doc(this.userDoc); + Doc.UserDoc().activeMobile = doc(this.userDoc); onSwitch && onSwitch(); this.renderView = renderView; } - onSwitchInking = () => { - Doc.SetSelectedTool(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) { @@ -102,36 +1032,531 @@ export default class MobileInterface extends React.Component { }); } - renderDefaultContent = () => { + @action + toggleSidebar = () => this.sidebarActive = !this.sidebarActive + + // toggleSidebar = () => { + // if (this._open === false) { + // this._open = true; + // } else { + // this._open = false; + // } + // console.log("clicked"); + // let menuButton = document.getElementById("menuButton") as HTMLElement; + // //menuButton.classList.toggle('active'); + + // let sidebar = document.getElementById("sidebar") as HTMLElement; + // //sidebar.classList.toggle('active'); + + // let header = document.getElementById("header") as HTMLElement; + + // if (!sidebar.classList.contains('active')) { + // header.textContent = String(this._activeDoc.title); + // } else { + // header.textContent = "library"; + // } + // } + + /** + * Method called when 'Library' button is pressed + */ + switchToLibrary = () => { + this._parents.push(this._activeDoc); + this.switchCurrentView((userDoc: Doc) => this._library); + this._activeDoc = this._library; + this._homeMenu = false; + this.sidebarActive = true; + } + + /** + * Back method for navigating within library + */ + back = () => { + let header = document.getElementById("header") as HTMLElement; + let doc = Cast(this._parents.pop(), Doc) as Doc; + if (doc === Cast(this._library, Doc) as Doc) { + this._child = null; + this.userDoc.activeMobile = this._library; + } else if (doc === Cast(this._homeDoc, Doc) as Doc) { + this._homeMenu = true; + this._parents = []; + this._activeDoc = this._homeDoc; + this._child = null; + this.switchCurrentView((userDoc: Doc) => this._homeDoc); + } else { + if (doc) { + this._child = doc; + this.switchCurrentView((userDoc: Doc) => doc); + this._homeMenu = false; + header.textContent = String(doc.title); + } + } + if (doc) { + this._activeDoc = doc; + } + this._ink = false; + } + + /** + * Return 'Home", which implies returning to 'Home' buttons + */ + returnHome = () => { + if (this._homeMenu === false || this.sidebarActive === true) { + this._homeMenu = true; + this._parents = []; + this._activeDoc = this._homeDoc; + this._child = null; + this.switchCurrentView((userDoc: Doc) => this._homeDoc); + } + if (this.sidebarActive) { + this.toggleSidebar(); + } + } + + /** + * Return to primary Workspace in library (Workspaces Doc) + */ + returnMain = () => { + console.log("home"); + this._parents = []; + // this.toggleSidebar(); + this._activeDoc = this._library; + this.switchCurrentView((userDoc: Doc) => this._library); + this._homeMenu = false; + this._child = null; + } + + // @computed get onChildClickHandler() { return ScriptCast(Doc.UserDoc.onClick); } + + /** + * DocumentView for graphic display of all documents + */ + displayWorkspaces = () => { if (this.mainContainer) { - return <DocumentView - Document={this.mainContainer} - DataDoc={undefined} - LibraryPath={emptyPath} - addDocument={returnFalse} - addDocTab={returnFalse} - pinToPres={emptyFunction} - rootSelected={returnFalse} - removeDocument={undefined} - onClick={undefined} - ScreenToLocalTransform={Transform.Identity} - ContentScaling={returnOne} - NativeHeight={returnZero} - NativeWidth={returnZero} - PanelWidth={() => window.screen.width} - PanelHeight={() => window.screen.height} - renderDepth={0} - focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - bringToFront={emptyFunction} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} />; + const backgroundColor = () => "white"; + if (this._activeDoc.title === "mobile audio") { + return ( + <div style={{ position: "relative", top: '600px', height: `calc(50% - 450px)`, width: "80%", overflow: "hidden", left: "10%", cursor: "pointer" }}> + <DocumentView + Document={this.mainContainer} + DataDoc={undefined} + LibraryPath={emptyPath} + addDocument={returnFalse} + addDocTab={returnFalse} + pinToPres={emptyFunction} + rootSelected={returnFalse} + removeDocument={undefined} + ScreenToLocalTransform={Transform.Identity} + ContentScaling={returnOne} + NativeHeight={returnZero} + NativeWidth={returnZero} + PanelWidth={() => window.screen.width} + PanelHeight={() => window.screen.height} + renderDepth={0} + focus={emptyFunction} + backgroundColor={backgroundColor} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + /> + </div> + ); + } else { + return ( + <div style={{ position: "relative", top: '200px', height: `calc(100% - 200px)`, width: "100%", overflow: "hidden", left: "0%" }}> + <DocumentView + Document={this.mainContainer} + DataDoc={undefined} + LibraryPath={emptyPath} + addDocument={returnFalse} + addDocTab={returnFalse} + pinToPres={emptyFunction} + rootSelected={returnFalse} + removeDocument={undefined} + onClick={undefined} + ScreenToLocalTransform={Transform.Identity} + ContentScaling={returnOne} + PanelWidth={this.returnWidth} + PanelHeight={this.returnHeight} + NativeHeight={returnZero} + NativeWidth={returnZero} + renderDepth={0} + focus={emptyFunction} + backgroundColor={backgroundColor} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + /> + </div> + ); + } + } + } + + returnWidth = () => window.innerWidth; //The windows width + returnHeight = () => (window.innerHeight - 300); //Calculating the windows height (-300 to account for topbar) + + /** + * Handles the click functionality in the library panel + * @param doc: doc for which the method is called + */ + handleClick(doc: Doc) { + let children = DocListCast(doc.data); + if (doc.type !== "collection") { + 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"); + } else { + this._parents.push(this._activeDoc); + this._activeDoc = doc; + this.switchCurrentView((userDoc: Doc) => doc); + this._homeMenu = false; + this._child = doc; + } + + // let sidebar = document.getElementById("sidebar") as HTMLElement; + // sidebar.classList.toggle('active'); + } + + /** + * Handles creation of array which is then rendered in renderPathbar() + */ + createPathname = () => { + // let pathname = 'workspaces'; + // let titleArray = []; + let docArray = []; + this._parents.map((doc: Doc, index: any) => { + docArray.push(doc); + }); + docArray.push(this._activeDoc); + return docArray; + } + + // Renders the graphical pathbar + renderPathbar = () => { + // if (this._homeMenu == false) { + let docArray = this.createPathname(); + let items = docArray.map((doc: Doc, index: any) => { + if (index === 0) { + return ( + <div className="pathbarItem"> + <div className="pathbarText" + key={index} + onClick={() => this.handlePathClick(doc, index)}>{doc.title} + </div> + </div>); + } else if (doc === this._activeDoc) { + return ( + <div className="pathbarItem"> + <FontAwesomeIcon className="pathIcon" icon="angle-right" size="lg" /> + <div className="pathbarText" + style={{ backgroundColor: "rgb(119, 37, 37)" }} + key={index} + onClick={() => this.handlePathClick(doc, index)}>{doc.title} + </div> + </div>); + } else { + return ( + <div className="pathbarItem"> + <FontAwesomeIcon className="pathIcon" icon="angle-right" size="lg" /> + <div className="pathbarText" + key={index} + onClick={() => this.handlePathClick(doc, index)}>{doc.title} + </div> + </div>); + } + + }); + if (this._parents.length !== 0) { + return (<div className="pathbar"> + <div className="scrollmenu"> + {items} + </div> + <div className="back" > + <FontAwesomeIcon onClick={this.back} icon={"chevron-left"} color="white" size={"2x"} /> + </div> + <div className="hidePath" /> + </div>); + } else { + return (<div className="pathbar"> + <div className="scrollmenu"> + {items} + </div> + <div className="hidePath" /> + </div>); + } + // } + // } else { + + // return ( + // <div className="pathbar"> + // <div className="scrollmenu"> + // <div className="pathbarItem"> + // <div className="pathbarText" + // style={{ backgroundColor: "rgb(119, 37, 37)" }} + // key={0} + // onClick={() => this.returnHome()}>Home + // </div> + // </div> + // </div> + // <div className="hidePath" /> + // </div> + // ); + // } + + // } + } + + // Handles when user clicks on document in the pathbar + handlePathClick = (doc: Doc, index: number) => { + if (doc === this._library) { + this._activeDoc = doc; + this._child = null; + this.switchCurrentView((userDoc: Doc) => doc); + this._parents.length = index; + } else if (doc === this._homeDoc) { + this.returnHome(); + } else { + this._activeDoc = doc; + this._child = doc; + this.switchCurrentView((userDoc: Doc) => doc); + this._parents.length = index; + } + } + + renderDefaultContent = () => { + let menuButtons = DocListCast(this._homeDoc.data).map((doc: Doc, index: any) => { + if (doc.type !== "ink") { + return ( + <div + className="item" + key={index} + onClick={() => doc.onClick}>{doc.title} + </div>); + } + }); + + if (this._homeMenu === true) { + return ( + <div> + <div className="navbar"> + <FontAwesomeIcon className="home" icon="home" onClick={this.returnHome} /> + <div className="header" id="header">{this._homeDoc.title}</div> + <div className="cover" id="cover" onClick={(e) => this.stop(e)}></div> + <div className="toggle-btn" id="menuButton" onClick={this.toggleSidebar}> + <span></span> + <span></span> + <span></span> + </div> + </div> + {this.renderPathbar()} + <div className="sidebar" id="sidebar"> + <div className="sidebarButtons"> + {menuButtons} + </div> + </div> + </div> + ); + } + + let workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc; + if (this._child) { + workspaces = this._child + } + + let buttons = DocListCast(workspaces.data).map((doc: Doc, index: any) => { + if (doc.type !== "ink") { + return ( + <div + className="item" + key={index} + onClick={() => this.handleClick(doc)}>{doc.title} + <div className="type">{doc.type}</div> + <FontAwesomeIcon className="right" icon="angle-right" size="lg" /> + </div>); + } + }); + + return ( + <div> + <div className="navbar"> + <FontAwesomeIcon className="home" icon="home" onClick={this.returnHome} /> + <div className="header" id="header">{this.sidebarActive ? "library" : this._activeDoc.title}</div> + <div className={`toggle-btn ${this.sidebarActive ? "active" : ""}`} onClick={this.toggleSidebar}> + <span></span> + <span></span> + <span></span> + </div> + </div> + {this.renderPathbar()} + <div className={`sidebar ${this.sidebarActive ? "active" : ""}`}> + <div className="sidebarButtons"> + {this._child ? + <> + {buttons} + <div className="item" key="home" onClick={this.returnMain}> + Return to library + </div> + </> : + <> + {buttons} + </> + } + </div> + </div> + </div> + ); + } + + stop = (e: React.MouseEvent) => { + e.stopPropagation(); + } + + uploadAudioButton = () => { + if (this._activeDoc.type === "audio") { + return <div className="docButton" + title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} + style={{ backgroundColor: "black", color: "white" }} + onClick={this.uploadAudio} + > + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="upload" + /> + </div>; + } + } + + + @action + toggleSelector = () => this.activeToolbar = !this.activeToolbar + + + colorTool = () => { + if (this._activeDoc._viewType === "docking") { + // const color = InkingControl.Instance.selectedColor; + const color = "lightpink"; + const selDoc = SelectionManager.SelectedDocuments()?.[0]?.rootDoc; + return ( + <div + className="docButton" + style={{ backgroundColor: color }} + onClick={this.toggleSelector} + > + <div className={`toolbar ${this.activeToolbar ? "active" : ""}`}> + <div className="colorSelector"> + {/* <SketchPicker onChange={InkingControl.Instance.switchColor} presetColors={['#D0021B', '#F5A623', '#F8E71C', '#8B572A', '#7ED321', '#417505', '#9013FE', '#4A90E2', '#50E3C2', '#B8E986', '#000000', '#4A4A4A', '#9B9B9B', '#FFFFFF', '#f1efeb', 'transparent']} */} + color={StrCast(CurrentUserUtils.ActivePen ? CurrentUserUtils.ActivePen.backgroundColor : undefined, + StrCast(selDoc?._backgroundColor, StrCast(selDoc?.backgroundColor, "black")))} /> + </div> + <div className="widthSelector"> + {/* <input type="range" min="1" max="100" defaultValue="2" id="myRange" onChange={(e: React.ChangeEvent<HTMLInputElement>) => InkingControl.Instance.switchWidth(e.target.value)} /> */} + </div> + </div> + </div> + ); + } + } + + onSwitchInking = () => { + const button = document.getElementById("inkButton") as HTMLElement; + // const color = InkingControl.Instance.selectedColor; + const color = "lightpink"; + button.style.backgroundColor = this._ink ? "white" : color; + button.style.color = this._ink ? "black" : "white"; + + if (!this._ink) { + console.log("INK IS ACTIVE"); + // InkingControl.Instance.switchTool(InkTool.Pen); + MobileInterface.Instance.drawingInk = true; + this._ink = true; + } else { + console.log("INK IS INACTIVE"); + // InkingControl.Instance.switchTool(InkTool.None); + MobileInterface.Instance.drawingInk = false; + this._ink = false; + } + } + + drawInk = () => { + if (this._activeDoc._viewType === "docking") { + const inkIsOn = this._ink; + return <div className="docButton" + id="inkButton" + title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"} + onClick={this.onSwitchInking}> + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="pen-nib" + /> + </div>; + } + } + + downloadDocument = () => { + if (this._activeDoc.type === "image") { + const url = this._activeDoc["data-path"]?.toString(); + return <div className="docButton" + title={"Download Image"} + style={{ backgroundColor: "white", color: "black" }} + onClick={e => { + window.open(url); + console.log(url); + }}> + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="download" + /> + </div>; + } + } + + recordAudio = async () => { + // upload to server with known URL + if (this._activeDoc.title !== "mobile audio") { + this._parents.push(this._activeDoc); + } + const audioDoc = Cast(Docs.Create.AudioDocument(nullAudio, { _width: 200, _height: 100, title: "mobile audio" }), Doc) as Doc; + if (audioDoc) { + this._activeDoc = audioDoc; + this.switchCurrentView((userDoc: Doc) => audioDoc); + this._homeMenu = false; + // this.toggleSidebar(); + } + // const audioRightSidebar = Cast(Doc.UserDoc().rightSidebarCollection, Doc) as Doc; + // this.audioState = await audioDoc.getProto; + // if (this.audioState) { + // console.log(this.audioState); + // const data = Cast(audioRightSidebar.data, listSpec(Doc)); + // if (data) { + // data.push(audioDoc); + // } + // } + } + + 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); } - return "hello"; + // this.recordAudio(); } + // renderActiveCollection = (userDoc: Doc) => { + // if (this.activeContainer) { + // const active = Cast(this.activeContainer.data, listSpec(Doc)); + // if (active) { + // return ( + // <div className="mobileInterface-background">HELLO!</div> + // ); + // } + // } + // } + onBack = (e: React.MouseEvent) => { this.switchCurrentView((userDoc: Doc) => this.mainDoc); Doc.SetSelectedTool(InkTool.None); // TODO: switch to previous tool @@ -164,61 +1589,15 @@ export default class MobileInterface extends React.Component { panelHeight = () => window.innerHeight; panelWidth = () => window.innerWidth; - renderInkingContent = () => { - console.log("rendering inking content"); - // TODO: support panning and zooming - // TODO: handle moving of ink strokes - if (this.mainContainer) { - return ( - <div className="mobileInterface"> - <div className="mobileInterface-inkInterfaceButtons"> - <div className="navButtons"> - <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing">BACK</button> - </div> - <div className="inkSettingButtons"> - <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button> - </div> - <div className="navButtons"> - <button className="mobileInterface-button" onClick={this.shiftLeft} title="Shift left">left</button> - <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button> - </div> - </div> - <CollectionView - Document={this.mainContainer} - DataDoc={undefined} - LibraryPath={emptyPath} - filterAddDocument={returnTrue} - fieldKey={""} - dropAction={"alias"} - bringToFront={emptyFunction} - addDocTab={returnFalse} - pinToPres={emptyFunction} - PanelWidth={this.panelWidth} - PanelHeight={this.panelHeight} - NativeHeight={returnZero} - NativeWidth={returnZero} - focus={emptyFunction} - isSelected={returnFalse} - select={emptyFunction} - active={returnFalse} - ContentScaling={returnOne} - whenActiveChanged={returnFalse} - ScreenToLocalTransform={Transform.Identity} - renderDepth={0} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - rootSelected={returnTrue}> - </CollectionView> - </div> - ); - } - } + //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 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 @@ -261,45 +1640,100 @@ export default class MobileInterface extends React.Component { } } - renderUploadContent() { - if (this.mainContainer) { + pinToPresentation = () => { + // Only making button available if it is an image + if (this._activeDoc.type === "image") { + const isPinned = this._activeDoc && Doc.isDocPinned(this._activeDoc); + return <div className="docButton" + title={Doc.isDocPinned(this._activeDoc) ? "Unpin from presentation" : "Pin to presentation"} + style={{ backgroundColor: isPinned ? "black" : "white", color: isPinned ? "white" : "black" }} + onClick={e => { + if (isPinned) { + DockedFrameRenderer.UnpinDoc(this._activeDoc); + } + else { + DockedFrameRenderer.PinDoc(this._activeDoc); + } + }}> + <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="map-pin" + /> + </div>; + } + } + + switchMenuView = () => { + if (this._activeDoc.title === this._homeDoc.title) { return ( - <div className="mobileInterface" onDragOver={this.onDragOver}> - <div className="mobileInterface-inkInterfaceButtons"> - <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button> - {/* <button className="mobileInterface-button" onClick={this.clearUpload} title="Clear Upload">CLEAR</button> */} - {/* <button className="mobileInterface-button" onClick={this.addWeb} title="Add Web Doc to Upload Collection"></button> */} - <button className="mobileInterface-button" onClick={this.upload} title="Upload">UPLOAD</button> + <div className="homeSwitch"> + <div className={`list ${!this.menuListView ? "active" : ""}`} onClick={this.changeToIconView}> + <FontAwesomeIcon size="sm" icon="th-large" /> + </div> + <div className={`list ${this.menuListView ? "active" : ""}`} onClick={this.changeToListView}> + <FontAwesomeIcon size="sm" icon="bars" /> </div> - <DocumentView - Document={this.mainContainer} - DataDoc={undefined} - LibraryPath={emptyPath} - addDocument={returnFalse} - addDocTab={returnFalse} - pinToPres={emptyFunction} - rootSelected={returnFalse} - removeDocument={undefined} - onClick={undefined} - ScreenToLocalTransform={Transform.Identity} - ContentScaling={returnOne} - NativeHeight={returnZero} - NativeWidth={returnZero} - PanelWidth={() => window.screen.width} - PanelHeight={() => window.screen.height} - renderDepth={0} - focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - bringToFront={emptyFunction} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} /> </div> ); } } + @action + changeToIconView = () => { + if (this._homeDoc._viewType = "stacking") { + this.menuListView = false; + this._homeDoc._viewType = "masonry"; + this._homeDoc.columnWidth = 300; + const menuButtons = DocListCast(this._homeDoc.data); + console.log('hello'); + menuButtons.map((doc: Doc, index: any) => { + console.log(index); + const buttonData = DocListCast(doc.data); + buttonData[1]._nativeWidth = 0.1; + buttonData[1]._width = 0.1; + buttonData[1]._dimMagnitude = 0; + buttonData[1]._opacity = 0; + console.log(buttonData); + console.log(doc._nativeWidth); + doc._nativeWidth = 400; + console.log(doc._nativeWidth); + }); + } + } + + @action + changeToListView = () => { + if (this._homeDoc._viewType = "masonry") { + this._homeDoc._viewType = "stacking"; + this.menuListView = true; + const menuButtons = DocListCast(this._homeDoc.data); + console.log('hello'); + menuButtons.map((doc: Doc, index: any) => { + const buttonData = DocListCast(doc.data); + buttonData[1]._nativeWidth = 450; + buttonData[1]._dimMagnitude = 2; + buttonData[1]._opacity = 1; + console.log(doc._nativeWidth); + doc._nativeWidth = 900; + console.log(doc._nativeWidth); + }); + } + } + + setupDefaultPresentation = () => { + if (this._activeDoc.title !== "Presentation") { + 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._homeMenu = false; + // this.toggleSidebar(); + } + } + onDragOver = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); @@ -308,37 +1742,189 @@ export default class MobileInterface extends React.Component { render() { // const content = this.currentView === "main" ? this.mainContent : // this.currentView === "ink" ? this.inkContent : - // this.currentView === "upload" ? this.uploadContent : <></>; + // this.currentView === "upload" ? this.uploadContent : <></>;onDragOver={this.onDragOver} return ( <div className="mobileInterface-container" onDragOver={this.onDragOver}> {/* <DocumentDecorations /> <GestureOverlay> {this.renderView ? this.renderView() : this.renderDefaultContent()} </GestureOverlay> */} - + {/* <GestureOverlay> */} + <SettingsManager /> + {/* {this.menuOptions()} */} + {/* {this.displayHome()} */} + <div className={`image-upload ${this.imageUploadActive ? "active" : ""}`}> + {this.uploadImage()} + </div> + {this.switchMenuView()} + <div className="docButtonContainer"> + {this.pinToPresentation()} + {this.downloadDocument()} + {this.drawInk()} + {this.uploadAudioButton()} + {this.colorTool()} + </div> + <GestureOverlay> + {this.displayWorkspaces()} + {this.renderDefaultContent()} + </GestureOverlay> + {/* </GestureOverlay> */} {/* <DictationOverlay /> <SharingManager /> <GoogleAuthenticationManager /> */} - <DocumentDecorations /> - <GestureOverlay> - {this.renderView ? this.renderView() : this.renderDefaultContent()} - </GestureOverlay> - <PreviewCursor /> + {/* <DocumentDecorations /> */} + {/* <div> + {this.renderDefaultContent()} + </div> */} + {/* <PreviewCursor /> */} {/* <ContextMenu /> */} - <RadialMenu /> - <RichTextMenu /> + {/* <RadialMenu /> + <RichTextMenu /> */} {/* <PDFMenu /> <MarqueeOptionsMenu /> <OverlayView /> */} </div> ); } + + @action + toggleUpload = () => this.imageUploadActive = !this.imageUploadActive + + + @action + closeUpload = () => { + this.imageUploadActive = false; + } + + // toggleUpload = () => { + // if (this.imageUploadActive === true) { + // this.imageUploadActive = false; + // } else { + // this.imageUploadActive = true; + // } + // } + + uploadImage = () => { + if (this.imageUploadActive) { + console.log("active"); + } else if (!this.imageUploadActive) { + + } + console.log("upload"); + return ( + <div> + <div className="closeUpload" onClick={this.toggleUpload}> + <FontAwesomeIcon icon="window-close" size={"lg"} /> + </div> + <Uploader /> + </div> + ); + } } + + +const inputRef = React.createRef<HTMLInputElement>(); + + Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); }); -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(); }); +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 openMobileSettings() { return SettingsManager.Instance.open(); }); +Scripting.addGlobal(function switchToLibrary() { return MobileInterface.Instance.switchToLibrary(); }); +Scripting.addGlobal(function uploadImageMobile() { return MobileInterface.Instance.toggleUpload(); }); + + + +// WAS 2 + +// 1 +// renderUploadContent() { +// if (this.mainContainer) { +// return ( +// <div className="mobileInterface" onDragOver={this.onDragOver}> +// <div className="mobileInterface-inkInterfaceButtons"> +// <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button> +// {/* <button className="mobileInterface-button" onClick={this.clearUpload} title="Clear Upload">CLEAR</button> */} +// {/* <button className="mobileInterface-button" onClick={this.addWeb} title="Add Web Doc to Upload Collection"></button> */} +// <button className="mobileInterface-button" onClick={this.upload} title="Upload">UPLOAD</button> +// </div> +// <DocumentView +// Document={this.mainContainer} +// DataDoc={undefined} +// LibraryPath={emptyPath} +// addDocument={returnFalse} +// addDocTab={returnFalse} +// pinToPres={emptyFunction} +// rootSelected={returnFalse} +// removeDocument={undefined} +// onClick={undefined} +// ScreenToLocalTransform={Transform.Identity} +// ContentScaling={returnOne} +// NativeHeight={returnZero} +// NativeWidth={returnZero} +// PanelWidth={() => window.screen.width} +// PanelHeight={() => window.screen.height} +// renderDepth={0} +// focus={emptyFunction} +// backgroundColor={returnEmptyString} +// parentActive={returnTrue} +// whenActiveChanged={emptyFunction} +// bringToFront={emptyFunction} +// ContainingCollectionView={undefined} +// ContainingCollectionDoc={undefined} /> +// </div> +// ); +// } +// } +// 3 + // renderInkingContent = () => { + // console.log("rendering inking content"); + // // TODO: support panning and zooming + // // TODO: handle moving of ink strokes + // if (this.mainContainer) { + // return ( + // <div className="mobileInterface"> + // <div className="mobileInterface-inkInterfaceButtons"> + // <div className="navButtons"> + // <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing">BACK</button> + // </div> + // <div className="inkSettingButtons"> + // <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button> + // </div> + // <div className="navButtons"> + // <button className="mobileInterface-button" onClick={this.shiftLeft} title="Shift left">left</button> + // <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button> + // </div> + // </div> + // <CollectionView + // Document={this.mainContainer} + // DataDoc={undefined} + // LibraryPath={emptyPath} + // fieldKey={""} + // dropAction={"alias"} + // bringToFront={emptyFunction} + // addDocTab={returnFalse} + // pinToPres={emptyFunction} + // PanelWidth={this.panelWidth} + // PanelHeight={this.panelHeight} + // NativeHeight={returnZero} + // NativeWidth={returnZero} + // focus={emptyFunction} + // isSelected={returnFalse} + // select={emptyFunction} + // active={returnFalse} + // ContentScaling={returnOne} + // whenActiveChanged={returnFalse} + // ScreenToLocalTransform={Transform.Identity} + // renderDepth={0} + // ContainingCollectionView={undefined} + // ContainingCollectionDoc={undefined} + // rootSelected={returnTrue}> + // </CollectionView> + // </div> + // ); + // } + // } diff --git a/src/mobile/MobileMain.tsx b/src/mobile/MobileMain.tsx new file mode 100644 index 000000000..3d4680d58 --- /dev/null +++ b/src/mobile/MobileMain.tsx @@ -0,0 +1,25 @@ +import { MobileInterface } from "./MobileInterface"; +import { Docs } from "../client/documents/Documents"; +import { CurrentUserUtils } from "../client/util/CurrentUserUtils"; +import * as ReactDOM from 'react-dom'; +import * as React from 'react'; +import { DocServer } from "../client/DocServer"; +import { AssignAllExtensions } from "../extensions/General/Extensions"; + +AssignAllExtensions(); + +(async () => { + const info = await CurrentUserUtils.loadCurrentUser(); + DocServer.init(window.location.protocol, window.location.hostname, 4321, info.email + " (mobile)"); + await Docs.Prototypes.initialize(); + if (info.id !== "__guest__") { + // a guest will not have an id registered + await CurrentUserUtils.loadUserDocument(info); + } + document.getElementById('root')!.addEventListener('wheel', event => { + if (event.ctrlKey) { + event.preventDefault(); + } + }, true); + ReactDOM.render(<MobileInterface />, document.getElementById('root')); +})();
\ No newline at end of file diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss new file mode 100644 index 000000000..16eb035b3 --- /dev/null +++ b/src/mobile/MobileMenu.scss @@ -0,0 +1,402 @@ +$navbar-height: 120px; +$pathbar-height: 50px; + +* { + margin: 0px; + padding: 0px; + box-sizing: border-box; + font-family: "Open Sans"; +} + +body { + overflow: hidden; +} + +.navbar { + position: fixed; + top: 0px; + left: 0px; + width: 100vw; + height: $navbar-height; + background-color: whitesmoke; + border-bottom: 5px solid black; +} + +.navbar .cover { + position: absolute; + right: 20px; + top: 30px; + height: 70px; + width: 70px; + background-color: whitesmoke; + z-index: 200; +} + +.navbar .toggle-btn { + position: absolute; + right: 20px; + top: 30px; + height: 70px; + width: 70px; + transition: all 300ms ease-in-out 200ms; +} + +.navbar .toggle-btn-home { + right: -200px; +} + +.navbar .header { + position: absolute; + top: 50%; + top: calc(9px + 50%); + right: 50%; + transform: translate(50%, -50%); + font-size: 40; + user-select: none; + text-transform: uppercase; + font-family: Arial, Helvetica, sans-serif; +} + +.navbar .toggle-btn span { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 70%; + height: 4px; + background: black; + transition: all 200ms ease; +} + +.navbar .toggle-btn span:nth-child(1) { + transition: top 200ms ease-in-out; + top: 30%; +} + +.navbar .toggle-btn span:nth-child(3) { + transition: top 200ms ease-in-out; + top: 70%; +} + +.navbar .toggle-btn.active { + transition: transform 200ms ease-in-out 200ms; + transform: rotate(135deg); +} + +.navbar .toggle-btn.active span:nth-child(1) { + top: 50%; +} + +.navbar .toggle-btn.active span:nth-child(2) { + transform: translate(-50%, -50%) rotate(90deg); +} + +.navbar .toggle-btn.active span:nth-child(3) { + top: 50%; +} + +.sidebar { + position: absolute; + top: 120px; + opacity: 0; + right: -100%; + width: 100%; + height: calc(100% - (120px)); + z-index: 101; + background-color: whitesmoke; + transition: all 400ms ease 50ms; + padding: 20px; + // overflow-y: auto; + // -webkit-overflow-scrolling: touch; + // border-right: 5px solid black; +} + +.sidebar .item { + width: 100%; + padding: 13px 12px; + border-bottom: 1px solid rgba(200, 200, 200, 0.7); + font-family: Arial, Helvetica, sans-serif; + font-style: normal; + font-weight: normal; + user-select: none; + font-size: 35px; + text-transform: uppercase; + color: black; + +} + +.sidebar .ink:focus { + outline: 1px solid blue; +} + +.sidebarButtons { + top: 80px; + position: relative; +} + +.home { + position: absolute; + top: 30px; + left: 30px; + font-size: 60; + user-select: none; + text-transform: uppercase; + font-family: Arial, Helvetica, sans-serif; + z-index: 200; +} + +.type { + display: inline; + text-transform: lowercase; + margin-left: 20px; + font-size: 35px; + font-style: italic; + color: rgb(28, 28, 28); +} + +.right { + margin-left: 20px; + z-index: 200; +} + +.left { + width: 100%; + height: 100%; +} + +.sidebar .logout { + width: 100%; + padding: 13px 12px; + border-bottom: 1px solid rgba(200, 200, 200, 0.7); + font-family: Arial, Helvetica, sans-serif; + font-style: normal; + font-weight: normal; + user-select: none; + font-size: 30px; + text-transform: uppercase; + color: black; +} + +.sidebar .settings { + width: 100%; + padding: 13px 12px; + border-bottom: 1px solid rgba(200, 200, 200, 0.7); + font-family: Arial, Helvetica, sans-serif; + font-style: normal; + font-weight: normal; + user-select: none; + font-size: 30px; + text-transform: uppercase; + color: black; +} + + +.sidebar.active { + right: 0%; + opacity: 1; +} + +.back { + position: absolute; + top: 44%; + left: 42px; + background-color: black; + width: 50px; + height: 50px; + text-align: center; + border-radius: 10px; + transform: translate(0, -50%); + font-size: 25px; + user-select: none; + z-index: 100; +} + +.pathbar { + position: absolute; + top: 118px; + left: 0px; + background: #1a1a1a; + z-index: 120; + border-radius: 0px; + width: 100%; + height: 80px; + transition: all 400ms ease 50ms; +} + +.pathname { + position: relative; + font-size: 25; + top: 50%; + width: 86%; + left: 12%; + color: whitesmoke; + transform: translate(0%, -50%); + z-index: 20; + font-family: sans-serif; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + direction: rtl; + text-align: left; + text-transform: uppercase; +} + +.docButton { + position: relative; + width: 100px; + height: 100px; + font-size: 90px; + text-align: center; + border-style: solid; + border-radius: 50px; + border-width: medium; + margin: 20px; + z-index: 100; +} + +.docButtonContainer { + top: 90%; + position: absolute; + display: flex; + transform: translate(-50%, 0); + left: 50%; + z-index: 100; +} + +.scrollmenu { + overflow: auto; + white-space: nowrap; +} + +.pathbarItem { + position: relative; + display: inline-flex; + color: whitesmoke; + text-align: center; + user-select: none; + transform: translate(100px, 0px); + font-size: 30px; + padding: 10px; + text-transform: uppercase; +} + +.pathbarText { + font-family: sans-serif; + text-align: center; + height: 50px; + padding: 10px; + background-color: rgb(48, 40, 40); + font-size: 30px; + border-radius: 10px; + text-transform: uppercase; + margin-left: 20px; + position: relative; +} + + +.pathIcon { + transform: translate(0px, 8px); + position: relative; +} + +.hidePath { + position: absolute; + height: 100%; + width: 200px; + left: 0px; + top: 0px; + background-image: linear-gradient(to right, #1a1a1a, rgba(255, 0, 0, 0)); + text-align: center; + user-select: none; + z-index: 99; +} + +.toolbar { + left: 50%; + transform: translate(-50%); + position: absolute; + height: max-content; + top: 0px; + border-radius: 20px; + background-color: lightgrey; + opacity: 0; + transition: all 400ms ease 50ms; +} + +.toolbar.active { + display: inline-block; + width: 300px; + padding: 5px; + opacity: 1; + height: max-content; + top: -450px; +} + +.toolbar .colorSelector { + display: inline-flex; + width: max-content; + padding: 5px; + height: max-content; + pointer-events: all; +} + +.widthSelector { + display: inline-flex; + width: max-content; + height: 100px; + padding: 10px; +} + +.slider { + -webkit-appearance: none; + /* Override default CSS styles */ + appearance: none; + width: 100%; + /* Full-width */ + height: 25px; + /* Specified height */ + background: #d3d3d3; + /* Grey background */ + outline: none; + /* Remove outline */ +} + +.colorButton { + width: 70px; + margin: 10px; + height: 70px; + border-style: solid; + border-width: 3px; + border-radius: 100%; +} + +.homeSwitch { + position: absolute; + top: 212; + right: 36px; + display: inline-flex; + width: max-content; + z-index: 99; + height: 70px; +} + +.list { + width: 70px; + height: 70px; + margin: 5; + padding: 10; + align-items: center; + text-align: center; + font-size: 50; + border-style: solid; + border-width: 3; + border-color: black; + background: whitesmoke; + align-self: center; + border-radius: 10px; +} + +.list.active { + color: darkred; + border-color: darkred; +}
\ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index bd1d3b5a9..a5fe6ad80 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -43,7 +43,7 @@ module.exports = { repl: ["./src/debug/Repl.tsx", 'webpack-hot-middleware/client?reload=true'], test: ["./src/debug/Test.tsx", 'webpack-hot-middleware/client?reload=true'], inkControls: ["./src/mobile/InkControls.tsx", 'webpack-hot-middleware/client?reload=true'], - imageUpload: ["./src/mobile/ImageUpload.tsx", 'webpack-hot-middleware/client?reload=true'], + mobileInterface: ["./src/mobile/MobileMain.tsx", 'webpack-hot-middleware/client?reload=true'], }, optimization: { noEmitOnErrors: true @@ -66,42 +66,42 @@ module.exports = { }, module: { rules: [{ - test: [/\.tsx?$/], - use: [{ - loader: 'ts-loader', - options: { - transpileOnly: true - } - }] - }, - { - test: /\.scss|css$/, - use: [{ - loader: "style-loader" + test: [/\.tsx?$/], + use: [{ + loader: 'ts-loader', + options: { + transpileOnly: true + } + }] }, { - loader: "css-loader" + test: /\.scss|css$/, + use: [{ + loader: "style-loader" + }, + { + loader: "css-loader" + }, + { + loader: "sass-loader" + } + ] }, { - loader: "sass-loader" + test: /\.(jpg|png|pdf)$/, + use: [{ + loader: 'file-loader' + }] + }, + { + test: /\.(png|jpg|gif)$/i, + use: [{ + loader: 'url-loader', + options: { + limit: 8192 + } + }] } - ] - }, - { - test: /\.(jpg|png|pdf)$/, - use: [{ - loader: 'file-loader' - }] - }, - { - test: /\.(png|jpg|gif)$/i, - use: [{ - loader: 'url-loader', - options: { - limit: 8192 - } - }] - } ] }, plugins, |