From a23fb4733c250b2be0124ad456af7da71f4fca00 Mon Sep 17 00:00:00 2001 From: Fawn Date: Mon, 13 Jan 2020 17:03:19 -0500 Subject: started creating mobile ink view --- src/server/authentication/models/current_user_utils.ts | 1 + 1 file changed, 1 insertion(+) (limited to 'src/server') diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 2ade6f102..71369b625 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -101,6 +101,7 @@ export class CurrentUserUtils { { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, + { title: "draw", icon: "mouse-pointer", click: 'switchMobileView("ink");', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, ]; 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, -- cgit v1.2.3-70-g09d2 From b4c2d2add2b863060ce559e49b3953f24050f162 Mon Sep 17 00:00:00 2001 From: Fawn Date: Tue, 14 Jan 2020 14:47:44 -0500 Subject: can add strokes to mobile ink --- src/client/views/collections/CollectionSubView.tsx | 3 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/mobile/MobileInterface.tsx | 108 +++++++++++++++------ .../authentication/models/current_user_utils.ts | 4 + 4 files changed, 87 insertions(+), 29 deletions(-) (limited to 'src/server') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 73dc7edc6..d8b575092 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -53,7 +53,9 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { protected createDropAndGestureTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this.dropDisposer && this.dropDisposer(); this.gestureDisposer && this.gestureDisposer(); + console.log("create drop", ele); if (ele) { + console.log("create drop 2", ele); this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this)); } @@ -135,7 +137,6 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { @undoBatch protected onGesture(e: Event, ge: GestureUtils.GestureEvent) { - } @undoBatch diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 84945c6e6..c3e131184 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -356,6 +356,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @undoBatch onGesture = (e: Event, ge: GestureUtils.GestureEvent) => { + console.log("on gesture"); switch (ge.gesture) { case GestureUtils.Gestures.Stroke: const points = ge.points; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 1e0920686..8d342d749 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -10,8 +10,10 @@ import { DocumentView } from '../client/views/nodes/DocumentView'; import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue } from '../Utils'; import { Transform } from '../client/util/Transform'; import { library } from '@fortawesome/fontawesome-svg-core'; -import { faPenNib, faHighlighter, faEraser, faMousePointer } from '@fortawesome/free-solid-svg-icons'; +import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice } from '@fortawesome/free-solid-svg-icons'; import { Scripting } from '../client/util/Scripting'; +import { CollectionFreeFormView } from '../client/views/collections/collectionFreeForm/CollectionFreeFormView'; +import GestureOverlay from '../client/views/GestureOverlay'; @observer export default class MobileInterface extends React.Component { @@ -35,52 +37,102 @@ export default class MobileInterface extends React.Component { } } - @action switchCurrentView = (view: "main" | "ink" | "library") => { this.currentView = view; } + @action + switchCurrentView = (view: "main" | "ink" | "library") => { + this.currentView = view; + + if (this.userDoc) { + switch (view) { + case "main": { + const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); + this.userDoc.activeMobile = doc; + break; + } + case "ink": { + const doc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); + this.userDoc.activeMobile = doc; + break; + } + } + } + } @computed get mainContent() { if (this.mainContainer) { - switch (this.currentView) { - case "main": - return window.screen.width} + PanelHeight={() => window.screen.height} + renderDepth={0} + focus={emptyFunction} + backgroundColor={returnEmptyString} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + zoomToScale={emptyFunction} + getScale={returnOne}> + ; + } + return "hello"; + } + + @computed + get inkContent() { + // return
INK
; + if (this.mainContainer) { + return ( + + window.screen.width} PanelHeight={() => window.screen.height} - renderDepth={0} + PanelWidth={() => window.screen.width} + annotationsKey={""} + isAnnotationOverlay={false} focus={emptyFunction} - backgroundColor={returnEmptyString} - parentActive={returnTrue} - whenActiveChanged={emptyFunction} - bringToFront={emptyFunction} + isSelected={returnTrue} // + select={emptyFunction} + active={returnTrue} // + ContentScaling={returnOne} + whenActiveChanged={returnFalse} + CollectionView={undefined} + ScreenToLocalTransform={Transform.Identity} + ruleProvider={undefined} + renderDepth={0} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} - zoomToScale={emptyFunction} - getScale={returnOne}> - ; - case "ink": - return
INK
; - case "library": - return
LIBRARY
; - } + chromeCollapsed={true}> +
+
+ ); } - return "hello"; } render() { - console.log("rendering mobile"); + const content = this.currentView === "main" ? this.mainContent : this.currentView === "ink" ? this.inkContent : <>; return (
- {this.mainContent} + {content}
); } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 71369b625..b40179fbc 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -140,6 +140,10 @@ export class CurrentUserUtils { }); } + static setupMobileInkingDoc(userDoc: Doc) { + return Docs.Create.FreeformDocument([], { x: 0, y: 0, width: 10, height: 20, title: "Mobile Inking", backgroundColor: "red" }); + } + // 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 setupToolsPanel(sidebarContainer: Doc, doc: Doc) { // setup a masonry view of all he creators -- cgit v1.2.3-70-g09d2 From 3cca58612cde96a3082ca8e190fe2166d531d556 Mon Sep 17 00:00:00 2001 From: Fawn Date: Tue, 14 Jan 2020 17:40:50 -0500 Subject: drawn strokes get added to mobile ink collection --- src/client/views/GestureOverlay.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 - .../collectionFreeForm/CollectionFreeFormView.tsx | 8 +-- src/mobile/MobileInterface.scss | 7 +++ src/mobile/MobileInterface.tsx | 62 ++++++++++++++-------- .../authentication/models/current_user_utils.ts | 2 +- 6 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 src/mobile/MobileInterface.scss (limited to 'src/server') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 632f2f0d6..4d487c032 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -231,9 +231,9 @@ export default class GestureOverlay extends Touchable { render() { return (
+ {this.currentStroke} {this.props.children} {this._palette} - {this.currentStroke}
); } } diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index d8b575092..e94f24f2c 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -53,9 +53,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { protected createDropAndGestureTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view this.dropDisposer && this.dropDisposer(); this.gestureDisposer && this.gestureDisposer(); - console.log("create drop", ele); if (ele) { - console.log("create drop 2", ele); this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this)); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c3e131184..8d376fb57 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -114,6 +114,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } private addDocument = (newBox: Doc) => { const added = this.props.addDocument(newBox); + console.log("adding doc from freeform", added); added && this.bringToFront(newBox); added && this.updateCluster(newBox); return added; @@ -356,12 +357,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @undoBatch onGesture = (e: Event, ge: GestureUtils.GestureEvent) => { - console.log("on gesture"); switch (ge.gesture) { case GestureUtils.Gestures.Stroke: const points = ge.points; const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { x: B.x, y: B.y, width: B.width, height: B.height }); + console.log("make stroke", inkDoc); this.addDocument(inkDoc); e.stopPropagation(); break; @@ -403,14 +404,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @action pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => { // I think it makes sense for the marquee menu to go away when panned. -syip2 - MarqueeOptionsMenu.Instance.fadeOut(true); + MarqueeOptionsMenu.Instance && MarqueeOptionsMenu.Instance.fadeOut(true); let x = this.Document.panX || 0; let y = this.Document.panY || 0; const docs = this.childLayoutPairs.map(pair => pair.layout); const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); if (!this.isAnnotationOverlay) { - PDFMenu.Instance.fadeOut(true); + PDFMenu.Instance && PDFMenu.Instance.fadeOut(true); const minx = docs.length ? NumCast(docs[0].x) : 0; const maxx = docs.length ? NumCast(docs[0].width) + minx : minx; const miny = docs.length ? NumCast(docs[0].y) : 0; @@ -990,6 +991,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document if (!this.extensionDoc) return (null); // let lodarea = this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale / this.props.ScreenToLocalTransform().Scale; + console.log("height freeform", this.isAnnotationOverlay, this.Document.scrollHeight, this.props.PanelHeight()); return
diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss new file mode 100644 index 000000000..e4cc919a5 --- /dev/null +++ b/src/mobile/MobileInterface.scss @@ -0,0 +1,7 @@ +.mobileInterface-topButtons { + position: absolute; + display: flex; + justify-content: space-between; + width: 100%; + z-index: 9999; +} \ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 8d342d749..3cb08afa7 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -10,10 +10,16 @@ import { DocumentView } from '../client/views/nodes/DocumentView'; import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue } from '../Utils'; import { Transform } from '../client/util/Transform'; import { library } from '@fortawesome/fontawesome-svg-core'; -import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice } from '@fortawesome/free-solid-svg-icons'; +import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck } from '@fortawesome/free-solid-svg-icons'; import { Scripting } from '../client/util/Scripting'; import { CollectionFreeFormView } from '../client/views/collections/collectionFreeForm/CollectionFreeFormView'; import GestureOverlay from '../client/views/GestureOverlay'; +import { InkingControl } from '../client/views/InkingControl'; +import { InkTool } from '../new_fields/InkField'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import "./MobileInterface.scss"; + +library.add(faTrash, faCheck); @observer export default class MobileInterface extends React.Component { @@ -22,6 +28,9 @@ export default class MobileInterface extends React.Component { @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } @observable private currentView: "main" | "ink" | "library" = "main"; + private mainDoc = CurrentUserUtils.setupMobileDoc(this.userDoc); + private inkDoc?: Doc; + constructor(props: Readonly<{}>) { super(props); MobileInterface.Instance = this; @@ -32,8 +41,8 @@ export default class MobileInterface extends React.Component { library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer]); if (this.userDoc && !this.mainContainer) { - const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); - this.userDoc.activeMobile = doc; + // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); + this.userDoc.activeMobile = this.mainDoc; } } @@ -44,13 +53,14 @@ export default class MobileInterface extends React.Component { if (this.userDoc) { switch (view) { case "main": { - const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); - this.userDoc.activeMobile = doc; + // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); + this.userDoc.activeMobile = this.mainDoc; break; } case "ink": { - const doc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); - this.userDoc.activeMobile = doc; + this.inkDoc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); + this.userDoc.activeMobile = this.inkDoc; + InkingControl.Instance.switchTool(InkTool.Pen); break; } } @@ -64,7 +74,7 @@ export default class MobileInterface extends React.Component { Document={this.mainContainer} DataDoc={undefined} LibraryPath={emptyPath} - addDocument={undefined} + addDocument={returnFalse} addDocTab={returnFalse} pinToPres={emptyFunction} removeDocument={undefined} @@ -89,40 +99,46 @@ export default class MobileInterface extends React.Component { return "hello"; } + onClick = (e: React.MouseEvent) => { + // insert ink as collection into active displayed doc view + // reset ink collection + this.inkDoc = undefined; + console.log("clicked"); + this.switchCurrentView("main"); + InkingControl.Instance.switchTool(InkTool.None); // TODO: switch to previous tool + } + @computed get inkContent() { - // return
INK
; + // TODO: get props from active collection and pass to the new freeform if (this.mainContainer) { return ( - + + +
+ window.screen.height} - PanelWidth={() => window.screen.width} - annotationsKey={""} - isAnnotationOverlay={false} + PanelHeight={() => window.innerHeight} + PanelWidth={() => window.innerWidth} focus={emptyFunction} - isSelected={returnTrue} // + isSelected={returnTrue} select={emptyFunction} - active={returnTrue} // + active={returnTrue} ContentScaling={returnOne} whenActiveChanged={returnFalse} - CollectionView={undefined} ScreenToLocalTransform={Transform.Identity} ruleProvider={undefined} renderDepth={0} ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - chromeCollapsed={true}> - + ContainingCollectionDoc={undefined}> + ); } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index b40179fbc..98092ddfe 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -141,7 +141,7 @@ export class CurrentUserUtils { } static setupMobileInkingDoc(userDoc: Doc) { - return Docs.Create.FreeformDocument([], { x: 0, y: 0, width: 10, height: 20, title: "Mobile Inking", backgroundColor: "red" }); + return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white" }); } // 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) -- cgit v1.2.3-70-g09d2 From 65e164eaec42d1850de7f5e1eba1d4302c3e8230 Mon Sep 17 00:00:00 2001 From: Fawn Date: Wed, 15 Jan 2020 16:08:48 -0500 Subject: mobile interface emits events when switched to inking view and when strokes are drawn, currently with dummy callbacks --- src/client/DocServer.ts | 22 ++++++++++++++++++- src/client/views/GestureOverlay.tsx | 21 ++++++++++++++++++ src/client/views/MainView.tsx | 13 +++++++++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 --- src/mobile/MobileInterface.tsx | 25 +++++++++++++++------- src/server/Message.ts | 13 +++++++++++ src/server/Websocket/Websocket.ts | 12 ++++++++++- 7 files changed, 94 insertions(+), 15 deletions(-) (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index ed7fbd7ba..cfd9612ed 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,10 +1,11 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, YoutubeQueryTypes } from "./../server/Message"; +import { MessageStore, YoutubeQueryTypes, GestureContent } from "./../server/Message"; import { Opt, Doc } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; import { RefField } from '../new_fields/RefField'; import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; +import GestureOverlay from './views/GestureOverlay'; /** * This class encapsulates the transfer and cross-client synchronization of @@ -64,6 +65,19 @@ export namespace DocServer { } } + export namespace Mobile { + + export function dispatchGesturePoints(content: GestureContent) { + Utils.Emit(_socket, MessageStore.GesturePoints, content); + } + + export function dispatchBoxTrigger(enableBox: boolean) { + // _socket.emit("dispatchBoxTrigger"); + Utils.Emit(_socket, MessageStore.MobileInkBoxTrigger, enableBox); + } + + } + export function init(protocol: string, hostname: string, port: number, identifier: string) { _cache = {}; GUID = identifier; @@ -85,6 +99,12 @@ export namespace DocServer { Utils.AddServerHandler(_socket, MessageStore.ConnectionTerminated, () => { alert("Your connection to the server has been terminated."); }); + _socket.addEventListener("receiveGesturePoints", (content: GestureContent) => { + GestureOverlay.Instance.manualDispatch(content); + }); + _socket.addEventListener("receiveBoxTrigger", (enableBox: boolean) => { + GestureOverlay.Instance.showBox(enableBox); + }); } function errorFunc(): never { diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 4d487c032..4b8dfa119 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -16,6 +16,10 @@ import { Scripting } from "../util/Scripting"; import { FieldValue, Cast } from "../../new_fields/Types"; import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; import Palette from "./Palette"; +import MobileInterface from "../../mobile/MobileInterface"; +import { MainView } from "./MainView"; +import { DocServer } from "../DocServer"; +import { GestureContent } from "../../server/Message"; @observer export default class GestureOverlay extends Touchable { @@ -35,6 +39,14 @@ export default class GestureOverlay extends Touchable { GestureOverlay.Instance = this; } + manualDispatch = (content: GestureContent) => { + console.log(content); + } + + showBox = (enableBox: boolean) => { + console.log("enable box?", enableBox); + } + @action handleHandDown = (e: React.TouchEvent) => { const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true); @@ -139,6 +151,15 @@ export default class GestureOverlay extends Touchable { const B = this.svgBounds; const points = this._points.map(p => ({ X: p.X - B.left, Y: p.Y - B.top })); + if (MobileInterface.Instance.drawingInk) { + const { selectedColor, selectedWidth } = InkingControl.Instance; + DocServer.Mobile.dispatchGesturePoints({ + points: this._points, + color: selectedColor, + width: selectedWidth + }); + } + const result = GestureUtils.GestureRecognizer.Recognize(new Array(points)); let actionPerformed = false; if (result && result.Score > 0.7) { diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 93fb0a07c..f1f7c37a3 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -49,6 +49,7 @@ export class MainView extends React.Component { private _flyoutSizeOnDown = 0; private _urlState: HistoryUtil.DocUrl; private _docBtnRef = React.createRef(); + private _mainViewRef = React.createRef(); @observable private _panelWidth: number = 0; @observable private _panelHeight: number = 0; @@ -507,8 +508,16 @@ export class MainView extends React.Component { return (null); } + get mainViewElement() { + return document.getElementById("mainView-container"); + } + + get mainViewRef() { + return this._mainViewRef; + } + render() { - return (
+ return (
@@ -518,7 +527,7 @@ export class MainView extends React.Component { - + diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8d376fb57..bbfd22f50 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -114,7 +114,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } private addDocument = (newBox: Doc) => { const added = this.props.addDocument(newBox); - console.log("adding doc from freeform", added); added && this.bringToFront(newBox); added && this.updateCluster(newBox); return added; @@ -362,7 +361,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { const points = ge.points; const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height); const inkDoc = Docs.Create.InkDocument(InkingControl.Instance.selectedColor, InkingControl.Instance.selectedTool, parseInt(InkingControl.Instance.selectedWidth), points, { x: B.x, y: B.y, width: B.width, height: B.height }); - console.log("make stroke", inkDoc); this.addDocument(inkDoc); e.stopPropagation(); break; @@ -991,7 +989,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // otherwise, they are stored in fieldKey. All annotations to this document are stored in the extension document if (!this.extensionDoc) return (null); // let lodarea = this.Document[WidthSym]() * this.Document[HeightSym]() / this.props.ScreenToLocalTransform().Scale / this.props.ScreenToLocalTransform().Scale; - console.log("height freeform", this.isAnnotationOverlay, this.Document.scrollHeight, this.props.PanelHeight()); return
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 3cb08afa7..1429226b4 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -2,7 +2,7 @@ import React = require('react'); import { observer } from 'mobx-react'; import { computed, action, observable } from 'mobx'; import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; -import { FieldValue, Cast } from '../new_fields/Types'; +import { FieldValue, Cast, StrCast } from '../new_fields/Types'; import { Doc } from '../new_fields/Doc'; import { Docs } from '../client/documents/Documents'; import { CollectionView } from '../client/views/collections/CollectionView'; @@ -18,6 +18,10 @@ import { InkingControl } from '../client/views/InkingControl'; import { InkTool } from '../new_fields/InkField'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import "./MobileInterface.scss"; +import { SelectionManager } from '../client/util/SelectionManager'; +import { DateField } from '../new_fields/DateField'; +import { GestureUtils } from '../pen-gestures/GestureUtils'; +import { DocServer } from '../client/DocServer'; library.add(faTrash, faCheck); @@ -30,6 +34,7 @@ export default class MobileInterface extends React.Component { private mainDoc = CurrentUserUtils.setupMobileDoc(this.userDoc); private inkDoc?: Doc; + public drawingInk: boolean = false; constructor(props: Readonly<{}>) { super(props); @@ -61,6 +66,10 @@ export default class MobileInterface extends React.Component { this.inkDoc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); this.userDoc.activeMobile = this.inkDoc; InkingControl.Instance.switchTool(InkTool.Pen); + this.drawingInk = true; + + DocServer.Mobile.dispatchBoxTrigger(true); + break; } } @@ -100,17 +109,17 @@ export default class MobileInterface extends React.Component { } onClick = (e: React.MouseEvent) => { - // insert ink as collection into active displayed doc view - // reset ink collection - this.inkDoc = undefined; - console.log("clicked"); this.switchCurrentView("main"); InkingControl.Instance.switchTool(InkTool.None); // TODO: switch to previous tool + + DocServer.Mobile.dispatchBoxTrigger(false); + + this.inkDoc = undefined; + this.drawingInk = false; } @computed get inkContent() { - // TODO: get props from active collection and pass to the new freeform if (this.mainContainer) { return ( @@ -128,9 +137,9 @@ export default class MobileInterface extends React.Component { PanelHeight={() => window.innerHeight} PanelWidth={() => window.innerWidth} focus={emptyFunction} - isSelected={returnTrue} + isSelected={returnFalse} select={emptyFunction} - active={returnTrue} + active={returnFalse} ContentScaling={returnOne} whenActiveChanged={returnFalse} ScreenToLocalTransform={Transform.Identity} diff --git a/src/server/Message.ts b/src/server/Message.ts index 621abfd1e..fe74dafa5 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -1,4 +1,5 @@ import { Utils } from "../Utils"; +import { Point } from "../pen-gestures/ndollar"; export class Message { private _name: string; @@ -42,6 +43,16 @@ export interface Diff extends Reference { readonly diff: any; } +export interface GestureContent { + readonly points: Array; + readonly width?: string; + readonly color?: string; +} + +export interface MobileInkBoxTriggerContent { + readonly enableBox: boolean; +} + export namespace MessageStore { export const Foo = new Message("Foo"); export const Bar = new Message("Bar"); @@ -51,6 +62,8 @@ export namespace MessageStore { export const GetDocument = new Message("Get Document"); export const DeleteAll = new Message("Delete All"); export const ConnectionTerminated = new Message("Connection Terminated"); + export const GesturePoints = new Message("Gesture Points"); + export const MobileInkBoxTrigger = new Message("Trigger Mobile Ink Box"); export const GetRefField = new Message("Get Ref Field"); export const GetRefFields = new Message("Get Ref Fields"); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index 578147d60..67777f023 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -1,5 +1,5 @@ import { Utils } from "../../Utils"; -import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes } from "../Message"; +import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent } from "../Message"; import { Client } from "../Client"; import { Socket } from "socket.io"; import { Database } from "../database"; @@ -54,6 +54,8 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); Utils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); + Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); + Utils.AddServerHandler(socket, MessageStore.MobileInkBoxTrigger, enableBox => processBoxTrigger(socket, enableBox)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); @@ -68,6 +70,14 @@ export namespace WebSocket { logPort("websocket", socketPort); } + function processGesturePoints(socket: Socket, content: GestureContent) { + socket.broadcast.emit("receiveGesturePoints", content); + } + + function processBoxTrigger(socket: Socket, enableBox: boolean) { + socket.broadcast.emit("receiveBoxTrigger", enableBox); + } + function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { const { ProjectCredentials } = GoogleCredentialsLoader; switch (query.type) { -- cgit v1.2.3-70-g09d2 From 43c4ff69d515b874f71f9c638a267cd896036854 Mon Sep 17 00:00:00 2001 From: Fawn Date: Wed, 15 Jan 2020 17:20:09 -0500 Subject: strokes from mobile interface get properly inserted into desktop with offset of the mobile ink overlay --- src/client/DocServer.ts | 12 +++---- src/client/views/GestureOverlay.scss | 4 +++ src/client/views/GestureOverlay.tsx | 70 ++++++++++++++++++++++++++++++------ src/mobile/MobileInterface.tsx | 12 +++++-- src/server/Message.ts | 7 ++-- src/server/Websocket/Websocket.ts | 8 ++--- 6 files changed, 89 insertions(+), 24 deletions(-) (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index cfd9612ed..132128182 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, YoutubeQueryTypes, GestureContent } from "./../server/Message"; +import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkBoxContent } from "./../server/Message"; import { Opt, Doc } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -71,9 +71,9 @@ export namespace DocServer { Utils.Emit(_socket, MessageStore.GesturePoints, content); } - export function dispatchBoxTrigger(enableBox: boolean) { + export function dispatchBoxTrigger(content: MobileInkBoxContent) { // _socket.emit("dispatchBoxTrigger"); - Utils.Emit(_socket, MessageStore.MobileInkBoxTrigger, enableBox); + Utils.Emit(_socket, MessageStore.MobileInkBoxTrigger, content); } } @@ -100,10 +100,10 @@ export namespace DocServer { alert("Your connection to the server has been terminated."); }); _socket.addEventListener("receiveGesturePoints", (content: GestureContent) => { - GestureOverlay.Instance.manualDispatch(content); + GestureOverlay.Instance.drawStrokeToMobileInkBox(content); }); - _socket.addEventListener("receiveBoxTrigger", (enableBox: boolean) => { - GestureOverlay.Instance.showBox(enableBox); + _socket.addEventListener("receiveBoxTrigger", (content: MobileInkBoxContent) => { + GestureOverlay.Instance.enableMobileInkBox(content); }); } diff --git a/src/client/views/GestureOverlay.scss b/src/client/views/GestureOverlay.scss index 31601efd4..2996b7073 100644 --- a/src/client/views/GestureOverlay.scss +++ b/src/client/views/GestureOverlay.scss @@ -5,4 +5,8 @@ top: 0; left: 0; touch-action: none; +} + +.mobileInkOverlay { + border: 5px dashed red; } \ No newline at end of file diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 4b8dfa119..7e74d1d33 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -19,7 +19,8 @@ import Palette from "./Palette"; import MobileInterface from "../../mobile/MobileInterface"; import { MainView } from "./MainView"; import { DocServer } from "../DocServer"; -import { GestureContent } from "../../server/Message"; +import { GestureContent, MobileInkBoxContent } from "../../server/Message"; +import { Point } from "../northstar/model/idea/idea"; @observer export default class GestureOverlay extends Touchable { @@ -30,6 +31,10 @@ export default class GestureOverlay extends Touchable { @observable public Color: string = "rgb(244, 67, 54)"; @observable public Width: number = 5; + @observable private showMobileInkOverlay: boolean = false; + @observable private mobileInkOverlaySize: { width: number, height: number } = { width: 500, height: 700 }; + @observable private mobileInkOverlayPosition: { x: number, y: number } = { x: 300, y: 0 }; + private _d1: Doc | undefined; private thumbIdentifier?: number; @@ -39,14 +44,6 @@ export default class GestureOverlay extends Touchable { GestureOverlay.Instance = this; } - manualDispatch = (content: GestureContent) => { - console.log(content); - } - - showBox = (enableBox: boolean) => { - console.log("enable box?", enableBox); - } - @action handleHandDown = (e: React.TouchEvent) => { const fingers = InteractionUtils.GetMyTargetTouches(e, this.prevPoints, true); @@ -151,10 +148,11 @@ export default class GestureOverlay extends Touchable { const B = this.svgBounds; const points = this._points.map(p => ({ X: p.X - B.left, Y: p.Y - B.top })); - if (MobileInterface.Instance.drawingInk) { + if (MobileInterface.Instance && MobileInterface.Instance.drawingInk) { const { selectedColor, selectedWidth } = InkingControl.Instance; DocServer.Mobile.dispatchGesturePoints({ points: this._points, + bounds: B, color: selectedColor, width: selectedWidth }); @@ -249,12 +247,64 @@ export default class GestureOverlay extends Touchable { ); } + drawStrokeToMobileInkBox = (content: GestureContent) => { + console.log(content); + const { points, bounds } = content; + + const B = { + right: bounds.right + this.mobileInkOverlayPosition.x, + left: bounds.left + this.mobileInkOverlayPosition.x, + bottom: bounds.bottom + this.mobileInkOverlayPosition.y, + top: bounds.top + this.mobileInkOverlayPosition.y, + width: bounds.width, + height: bounds.height + }; + + const target = document.elementFromPoint(points[0].X, points[0].Y); + target?.dispatchEvent( + new CustomEvent("dashOnGesture", + { + bubbles: true, + detail: { + points: points, + gesture: GestureUtils.Gestures.Stroke, + bounds: B + } + } + ) + ); + } + + @action + enableMobileInkBox = (content: MobileInkBoxContent) => { + const { enableBox, width, height } = content; + console.log("enable box?", enableBox, width, height); + this.showMobileInkOverlay = enableBox; + this.mobileInkOverlaySize = { width: width ? width : 0, height: height ? height : 0 }; + this.mobileInkOverlayPosition = { x: 300, y: 25 }; // TODO put at center of screen + + } + + @computed get mobileInkOverlay() { + return ( +
+ ); + } + render() { return (
{this.currentStroke} {this.props.children} {this._palette} + {this.showMobileInkOverlay ? this.mobileInkOverlay : <>}
); } } diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 1429226b4..4840ea374 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -68,7 +68,11 @@ export default class MobileInterface extends React.Component { InkingControl.Instance.switchTool(InkTool.Pen); this.drawingInk = true; - DocServer.Mobile.dispatchBoxTrigger(true); + DocServer.Mobile.dispatchBoxTrigger({ + enableBox: true, + width: window.innerWidth, + height: window.innerHeight + }); break; } @@ -112,7 +116,11 @@ export default class MobileInterface extends React.Component { this.switchCurrentView("main"); InkingControl.Instance.switchTool(InkTool.None); // TODO: switch to previous tool - DocServer.Mobile.dispatchBoxTrigger(false); + DocServer.Mobile.dispatchBoxTrigger({ + enableBox: false, + width: window.innerWidth, + height: window.innerHeight + }); this.inkDoc = undefined; this.drawingInk = false; diff --git a/src/server/Message.ts b/src/server/Message.ts index fe74dafa5..1958286df 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -45,12 +45,15 @@ export interface Diff extends Reference { export interface GestureContent { readonly points: Array; + readonly bounds: { right: number, left: number, bottom: number, top: number, width: number, height: number }; readonly width?: string; readonly color?: string; } -export interface MobileInkBoxTriggerContent { +export interface MobileInkBoxContent { readonly enableBox: boolean; + readonly width?: number; + readonly height?: number; } export namespace MessageStore { @@ -63,7 +66,7 @@ export namespace MessageStore { export const DeleteAll = new Message("Delete All"); export const ConnectionTerminated = new Message("Connection Terminated"); export const GesturePoints = new Message("Gesture Points"); - export const MobileInkBoxTrigger = new Message("Trigger Mobile Ink Box"); + export const MobileInkBoxTrigger = new Message("Trigger Mobile Ink Box"); export const GetRefField = new Message("Get Ref Field"); export const GetRefFields = new Message("Get Ref Fields"); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index 67777f023..16e34bdfc 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -1,5 +1,5 @@ import { Utils } from "../../Utils"; -import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent } from "../Message"; +import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkBoxContent } from "../Message"; import { Client } from "../Client"; import { Socket } from "socket.io"; import { Database } from "../database"; @@ -55,7 +55,7 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); - Utils.AddServerHandler(socket, MessageStore.MobileInkBoxTrigger, enableBox => processBoxTrigger(socket, enableBox)); + Utils.AddServerHandler(socket, MessageStore.MobileInkBoxTrigger, content => processBoxTrigger(socket, content)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); @@ -74,8 +74,8 @@ export namespace WebSocket { socket.broadcast.emit("receiveGesturePoints", content); } - function processBoxTrigger(socket: Socket, enableBox: boolean) { - socket.broadcast.emit("receiveBoxTrigger", enableBox); + function processBoxTrigger(socket: Socket, content: MobileInkBoxContent) { + socket.broadcast.emit("receiveBoxTrigger", content); } function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { -- cgit v1.2.3-70-g09d2 From ecf0f5b8f426db9e66c05e759f61294811b15fca Mon Sep 17 00:00:00 2001 From: vellichora Date: Sat, 1 Feb 2020 14:56:19 -0500 Subject: mobile ink overlay is draggable from desktop --- src/client/DocServer.ts | 19 ++- src/client/util/InteractionUtils.ts | 165 ------------------- src/client/util/InteractionUtils.tsx | 182 +++++++++++++++++++++ src/client/views/GestureOverlay.scss | 4 - src/client/views/GestureOverlay.tsx | 25 +-- src/client/views/InkingStroke.tsx | 17 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 - src/client/views/nodes/DocumentView.tsx | 1 + src/mobile/MobileInkOverlay.scss | 38 +++++ src/mobile/MobileInkOverlay.tsx | 91 +++++++++-- src/mobile/MobileInterface.scss | 2 +- src/mobile/MobileInterface.tsx | 90 ++++++---- src/server/Message.ts | 14 +- src/server/Websocket/Websocket.ts | 8 +- 14 files changed, 393 insertions(+), 264 deletions(-) delete mode 100644 src/client/util/InteractionUtils.ts create mode 100644 src/client/util/InteractionUtils.tsx create mode 100644 src/mobile/MobileInkOverlay.scss (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index a1cb42df2..b20cd3521 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkBoxContent } from "./../server/Message"; +import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPosition } from "./../server/Message"; import { Opt, Doc } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -72,9 +72,13 @@ export namespace DocServer { Utils.Emit(_socket, MessageStore.GesturePoints, content); } - export function dispatchBoxTrigger(content: MobileInkBoxContent) { + export function dispatchOverlayTrigger(content: MobileInkOverlayContent) { // _socket.emit("dispatchBoxTrigger"); - Utils.Emit(_socket, MessageStore.MobileInkBoxTrigger, content); + Utils.Emit(_socket, MessageStore.MobileInkOverlayTrigger, content); + } + + export function dispatchOverlayPositionUpdate(content: UpdateMobileInkOverlayPosition) { + Utils.Emit(_socket, MessageStore.UpdateMobileInkOverlayPosition, content); } } @@ -100,13 +104,18 @@ export namespace DocServer { Utils.AddServerHandler(_socket, MessageStore.ConnectionTerminated, () => { alert("Your connection to the server has been terminated."); }); + + // mobile ink overlay socket events to communicate between mobile view and desktop view _socket.addEventListener("receiveGesturePoints", (content: GestureContent) => { MobileInkOverlay.Instance.drawStroke(content); }); - _socket.addEventListener("receiveBoxTrigger", (content: MobileInkBoxContent) => { - GestureOverlay.Instance.enableMobileInkBox(content); + _socket.addEventListener("receiveOverlayTrigger", (content: MobileInkOverlayContent) => { + GestureOverlay.Instance.enableMobileInkOverlay(content); MobileInkOverlay.Instance.initMobileInkOverlay(content); }); + _socket.addEventListener("updateMobileOverlayPosition", (content: UpdateMobileInkOverlayPosition) => { + MobileInkOverlay.Instance.updatePosition(content); + }); } function errorFunc(): never { diff --git a/src/client/util/InteractionUtils.ts b/src/client/util/InteractionUtils.ts deleted file mode 100644 index 76b43da3c..000000000 --- a/src/client/util/InteractionUtils.ts +++ /dev/null @@ -1,165 +0,0 @@ -export namespace InteractionUtils { - export const MOUSETYPE = "mouse"; - export const TOUCHTYPE = "touch"; - export const PENTYPE = "pen"; - export const ERASERTYPE = "eraser"; - - const POINTER_PEN_BUTTON = -1; - const REACT_POINTER_PEN_BUTTON = 0; - const ERASER_BUTTON = 5; - - export function GetMyTargetTouches(e: TouchEvent | React.TouchEvent, prevPoints: Map, ignorePen: boolean): React.Touch[] { - const myTouches = new Array(); - for (let i = 0; i < e.targetTouches.length; i++) { - const pt: any = e.targetTouches.item(i); - if (pt && prevPoints.has(pt.identifier)) { - if (ignorePen || (pt.radiusX > 1 && pt.radiusY > 1)) { - myTouches.push(pt); - } - } - } - return myTouches; - } - - export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean { - switch (type) { - // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2 - case PENTYPE: - return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0); - case ERASERTYPE: - return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON); - default: - return e.pointerType === type; - } - } - - export function TwoPointEuclidist(pt1: React.Touch, pt2: React.Touch): number { - return Math.sqrt(Math.pow(pt1.clientX - pt2.clientX, 2) + Math.pow(pt1.clientY - pt2.clientY, 2)); - } - - /** - * Returns the centroid of an n-arbitrary long list of points (takes the average the x and y components of each point) - * @param pts - n-arbitrary long list of points - */ - export function CenterPoint(pts: React.Touch[]): { X: number, Y: number } { - const centerX = pts.map(pt => pt.clientX).reduce((a, b) => a + b, 0) / pts.length; - const centerY = pts.map(pt => pt.clientY).reduce((a, b) => a + b, 0) / pts.length; - return { X: centerX, Y: centerY }; - } - - /** - * Returns -1 if pinching out, 0 if not pinching, and 1 if pinching in - * @param pt1 - new point that corresponds to oldPoint1 - * @param pt2 - new point that corresponds to oldPoint2 - * @param oldPoint1 - previous point 1 - * @param oldPoint2 - previous point 2 - */ - export function Pinching(pt1: React.Touch, pt2: React.Touch, oldPoint1: React.Touch, oldPoint2: React.Touch): number { - const threshold = 4; - const oldDist = TwoPointEuclidist(oldPoint1, oldPoint2); - const newDist = TwoPointEuclidist(pt1, pt2); - - /** if they have the same sign, then we are either pinching in or out. - * threshold it by 10 (it has to be pinching by at least threshold to be a valid pinch) - * so that it can still pan without freaking out - */ - if (Math.sign(oldDist) === Math.sign(newDist) && Math.abs(oldDist - newDist) > threshold) { - return Math.sign(oldDist - newDist); - } - return 0; - } - - /** - * Returns -1 if pinning and pinching out, 0 if not pinning, and 1 if pinching in - * @param pt1 - new point that corresponds to oldPoint1 - * @param pt2 - new point that corresponds to oldPoint2 - * @param oldPoint1 - previous point 1 - * @param oldPoint2 - previous point 2 - */ - export function Pinning(pt1: React.Touch, pt2: React.Touch, oldPoint1: React.Touch, oldPoint2: React.Touch): number { - const threshold = 4; - - const pt1Dist = TwoPointEuclidist(oldPoint1, pt1); - const pt2Dist = TwoPointEuclidist(oldPoint2, pt2); - - const pinching = Pinching(pt1, pt2, oldPoint1, oldPoint2); - - if (pinching !== 0) { - if ((pt1Dist < threshold && pt2Dist > threshold) || (pt1Dist > threshold && pt2Dist < threshold)) { - return pinching; - } - } - return 0; - } - - export function IsDragging(oldTouches: Map, newTouches: React.Touch[], leniency: number): boolean { - for (const touch of newTouches) { - if (touch) { - const oldTouch = oldTouches.get(touch.identifier); - if (oldTouch) { - if (TwoPointEuclidist(touch, oldTouch) >= leniency) { - return true; - } - } - } - } - return false; - } - - // These might not be very useful anymore, but I'll leave them here for now -syip2 - { - - - /** - * Returns the type of Touch Interaction from a list of points. - * Also returns any data that is associated with a Touch Interaction - * @param pts - List of points - */ - // export function InterpretPointers(pts: React.Touch[]): { type: Opt, data?: any } { - // const leniency = 200; - // switch (pts.length) { - // case 1: - // return { type: OneFinger }; - // case 2: - // return { type: TwoSeperateFingers }; - // case 3: - // let pt1 = pts[0]; - // let pt2 = pts[1]; - // let pt3 = pts[2]; - // if (pt1 && pt2 && pt3) { - // let dist12 = TwoPointEuclidist(pt1, pt2); - // let dist23 = TwoPointEuclidist(pt2, pt3); - // let dist13 = TwoPointEuclidist(pt1, pt3); - // console.log(`distances: ${dist12}, ${dist23}, ${dist13}`); - // let dist12close = dist12 < leniency; - // let dist23close = dist23 < leniency; - // let dist13close = dist13 < leniency; - // let xor2313 = dist23close ? !dist13close : dist13close; - // let xor = dist12close ? !xor2313 : xor2313; - // // three input xor because javascript doesn't have logical xor's - // if (xor) { - // let points: number[] = []; - // let min = Math.min(dist12, dist23, dist13); - // switch (min) { - // case dist12: - // points = [0, 1, 2]; - // break; - // case dist23: - // points = [1, 2, 0]; - // break; - // case dist13: - // points = [0, 2, 1]; - // break; - // } - // return { type: TwoToOneFingers, data: points }; - // } - // else { - // return { type: ThreeSeperateFingers, data: null }; - // } - // } - // default: - // return { type: undefined }; - // } - // } - } -} \ No newline at end of file diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx new file mode 100644 index 000000000..34c7cfa74 --- /dev/null +++ b/src/client/util/InteractionUtils.tsx @@ -0,0 +1,182 @@ +import React = require("react"); + +export namespace InteractionUtils { + export const MOUSETYPE = "mouse"; + export const TOUCHTYPE = "touch"; + export const PENTYPE = "pen"; + export const ERASERTYPE = "eraser"; + + const POINTER_PEN_BUTTON = -1; + const REACT_POINTER_PEN_BUTTON = 0; + const ERASER_BUTTON = 5; + + export function GetMyTargetTouches(e: TouchEvent | React.TouchEvent, prevPoints: Map, ignorePen: boolean): React.Touch[] { + const myTouches = new Array(); + for (let i = 0; i < e.targetTouches.length; i++) { + const pt: any = e.targetTouches.item(i); + if (pt && prevPoints.has(pt.identifier)) { + if (ignorePen || (pt.radiusX > 1 && pt.radiusY > 1)) { + myTouches.push(pt); + } + } + } + return myTouches; + } + + // TODO: find a way to reference this function from InkingStroke instead of copy pastign here. copied bc of weird error when on mobile view + export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: number) { + const pts = points.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${pt.X - left},${pt.Y - top} `, ""); + return ( + + ); + } + + export function IsType(e: PointerEvent | React.PointerEvent, type: string): boolean { + switch (type) { + // pen and eraser are both pointer type 'pen', but pen is button 0 and eraser is button 5. -syip2 + case PENTYPE: + return e.pointerType === PENTYPE && (e.button === -1 || e.button === 0); + case ERASERTYPE: + return e.pointerType === PENTYPE && e.button === (e instanceof PointerEvent ? ERASER_BUTTON : ERASER_BUTTON); + default: + return e.pointerType === type; + } + } + + export function TwoPointEuclidist(pt1: React.Touch, pt2: React.Touch): number { + return Math.sqrt(Math.pow(pt1.clientX - pt2.clientX, 2) + Math.pow(pt1.clientY - pt2.clientY, 2)); + } + + /** + * Returns the centroid of an n-arbitrary long list of points (takes the average the x and y components of each point) + * @param pts - n-arbitrary long list of points + */ + export function CenterPoint(pts: React.Touch[]): { X: number, Y: number } { + const centerX = pts.map(pt => pt.clientX).reduce((a, b) => a + b, 0) / pts.length; + const centerY = pts.map(pt => pt.clientY).reduce((a, b) => a + b, 0) / pts.length; + return { X: centerX, Y: centerY }; + } + + /** + * Returns -1 if pinching out, 0 if not pinching, and 1 if pinching in + * @param pt1 - new point that corresponds to oldPoint1 + * @param pt2 - new point that corresponds to oldPoint2 + * @param oldPoint1 - previous point 1 + * @param oldPoint2 - previous point 2 + */ + export function Pinching(pt1: React.Touch, pt2: React.Touch, oldPoint1: React.Touch, oldPoint2: React.Touch): number { + const threshold = 4; + const oldDist = TwoPointEuclidist(oldPoint1, oldPoint2); + const newDist = TwoPointEuclidist(pt1, pt2); + + /** if they have the same sign, then we are either pinching in or out. + * threshold it by 10 (it has to be pinching by at least threshold to be a valid pinch) + * so that it can still pan without freaking out + */ + if (Math.sign(oldDist) === Math.sign(newDist) && Math.abs(oldDist - newDist) > threshold) { + return Math.sign(oldDist - newDist); + } + return 0; + } + + /** + * Returns -1 if pinning and pinching out, 0 if not pinning, and 1 if pinching in + * @param pt1 - new point that corresponds to oldPoint1 + * @param pt2 - new point that corresponds to oldPoint2 + * @param oldPoint1 - previous point 1 + * @param oldPoint2 - previous point 2 + */ + export function Pinning(pt1: React.Touch, pt2: React.Touch, oldPoint1: React.Touch, oldPoint2: React.Touch): number { + const threshold = 4; + + const pt1Dist = TwoPointEuclidist(oldPoint1, pt1); + const pt2Dist = TwoPointEuclidist(oldPoint2, pt2); + + const pinching = Pinching(pt1, pt2, oldPoint1, oldPoint2); + + if (pinching !== 0) { + if ((pt1Dist < threshold && pt2Dist > threshold) || (pt1Dist > threshold && pt2Dist < threshold)) { + return pinching; + } + } + return 0; + } + + export function IsDragging(oldTouches: Map, newTouches: React.Touch[], leniency: number): boolean { + for (const touch of newTouches) { + if (touch) { + const oldTouch = oldTouches.get(touch.identifier); + if (oldTouch) { + if (TwoPointEuclidist(touch, oldTouch) >= leniency) { + return true; + } + } + } + } + return false; + } + + // These might not be very useful anymore, but I'll leave them here for now -syip2 + { + + + /** + * Returns the type of Touch Interaction from a list of points. + * Also returns any data that is associated with a Touch Interaction + * @param pts - List of points + */ + // export function InterpretPointers(pts: React.Touch[]): { type: Opt, data?: any } { + // const leniency = 200; + // switch (pts.length) { + // case 1: + // return { type: OneFinger }; + // case 2: + // return { type: TwoSeperateFingers }; + // case 3: + // let pt1 = pts[0]; + // let pt2 = pts[1]; + // let pt3 = pts[2]; + // if (pt1 && pt2 && pt3) { + // let dist12 = TwoPointEuclidist(pt1, pt2); + // let dist23 = TwoPointEuclidist(pt2, pt3); + // let dist13 = TwoPointEuclidist(pt1, pt3); + // console.log(`distances: ${dist12}, ${dist23}, ${dist13}`); + // let dist12close = dist12 < leniency; + // let dist23close = dist23 < leniency; + // let dist13close = dist13 < leniency; + // let xor2313 = dist23close ? !dist13close : dist13close; + // let xor = dist12close ? !xor2313 : xor2313; + // // three input xor because javascript doesn't have logical xor's + // if (xor) { + // let points: number[] = []; + // let min = Math.min(dist12, dist23, dist13); + // switch (min) { + // case dist12: + // points = [0, 1, 2]; + // break; + // case dist23: + // points = [1, 2, 0]; + // break; + // case dist13: + // points = [0, 2, 1]; + // break; + // } + // return { type: TwoToOneFingers, data: points }; + // } + // else { + // return { type: ThreeSeperateFingers, data: null }; + // } + // } + // default: + // return { type: undefined }; + // } + // } + } +} \ No newline at end of file diff --git a/src/client/views/GestureOverlay.scss b/src/client/views/GestureOverlay.scss index 2996b7073..31601efd4 100644 --- a/src/client/views/GestureOverlay.scss +++ b/src/client/views/GestureOverlay.scss @@ -5,8 +5,4 @@ top: 0; left: 0; touch-action: none; -} - -.mobileInkOverlay { - border: 5px dashed red; } \ No newline at end of file diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 81284b543..a01a86b53 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -19,7 +19,7 @@ import Palette from "./Palette"; import MobileInterface from "../../mobile/MobileInterface"; import { MainView } from "./MainView"; import { DocServer } from "../DocServer"; -import { GestureContent, MobileInkBoxContent } from "../../server/Message"; +import { GestureContent, MobileInkOverlayContent } from "../../server/Message"; import { Point } from "../northstar/model/idea/idea"; import MobileInkOverlay from "../../mobile/MobileInkOverlay"; @@ -217,21 +217,6 @@ export default class GestureOverlay extends Touchable { return { right: right, left: left, bottom: bottom, top: top, width: right - left, height: bottom - top }; } - // TODO: find a way to reference this function from InkingStroke instead of copy pastign here. copied bc of weird error when on mobile view - CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color?: string, width?: number) { - const pts = points.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${pt.X - left},${pt.Y - top} `, ""); - return ( - - ); - } - @computed get currentStroke() { if (this._points.length <= 1) { return (null); @@ -241,23 +226,23 @@ export default class GestureOverlay extends Touchable { return ( - {this.CreatePolyline(this._points, B.left, B.top, this.Color, this.Width)} + {InteractionUtils.CreatePolyline(this._points, B.left, B.top, this.Color, this.Width)} ); } @action - enableMobileInkBox = (content: MobileInkBoxContent) => { - this.showMobileInkOverlay = content.enableBox; + enableMobileInkOverlay = (content: MobileInkOverlayContent) => { + this.showMobileInkOverlay = content.enableOverlay; } render() { return (
+ {this.showMobileInkOverlay ? : <>} {this.currentStroke} {this.props.children} {this._palette} - {this.showMobileInkOverlay ? : <>}
); } } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 8b346d5d9..aca507147 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -10,24 +10,11 @@ import "./InkingStroke.scss"; import { FieldView, FieldViewProps } from "./nodes/FieldView"; import React = require("react"); import { TraceMobx } from "../../new_fields/util"; +import { InteractionUtils } from "../util/InteractionUtils"; type InkDocument = makeInterface<[typeof documentSchema]>; const InkDocument = makeInterface(documentSchema); -export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color?: string, width?: number) { - const pts = points.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${pt.X - left},${pt.Y - top} `, ""); - return ( - - ); -} - @observer export class InkingStroke extends DocExtendableComponent(InkDocument) { public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); } @@ -44,7 +31,7 @@ export class InkingStroke extends DocExtendableComponent(Docu if (!(InteractionUtils.IsType(e, InteractionUtils.MOUSETYPE) || InkingControl.Instance.selectedTool === InkTool.Highlighter || InkingControl.Instance.selectedTool === InkTool.Pen)) { if (!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) { e.stopPropagation(); + // TODO: check here for panning/inking } return; } diff --git a/src/mobile/MobileInkOverlay.scss b/src/mobile/MobileInkOverlay.scss new file mode 100644 index 000000000..2e45d0441 --- /dev/null +++ b/src/mobile/MobileInkOverlay.scss @@ -0,0 +1,38 @@ +.mobileInkOverlay { + border: 5px dashed red; +} + +.mobileInkOverlay-border { + background-color: rgba(0, 255, 0, .4); + position: absolute; + pointer-events: auto; + cursor: pointer; + + &.top { + width: calc(100% + 20px); + height: 10px; + top: -10px; + left: -10px; + } + + &.left { + width: 10px; + height: calc(100% + 20px); + top: -10px; + left: -10px; + } + + &.right { + width: 10px; + height: calc(100% + 20px); + top: -10px; + right: -10px; + } + + &.bottom { + width: calc(100% + 20px); + height: 10px; + bottom: -10px; + left: -10px; + } +} \ No newline at end of file diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 71dd20c51..5efc7b83a 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,8 +1,9 @@ import React = require('react'); import { observer } from "mobx-react"; -import { MobileInkBoxContent, GestureContent } from "../server/Message"; +import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPosition } from "../server/Message"; import { observable, action } from "mobx"; import { GestureUtils } from "../pen-gestures/GestureUtils"; +import "./MobileInkOverlay.scss"; @observer @@ -15,6 +16,11 @@ export default class MobileInkOverlay extends React.Component { @observable private _x: number = -300; @observable private _y: number = -300; + @observable private _offsetX: number = 0; + @observable private _offsetY: number = 0; + @observable private _isDragging: boolean = false; + private _mainCont: React.RefObject = React.createRef(); + constructor(props: Readonly<{}>) { super(props); MobileInkOverlay.Instance = this; @@ -28,18 +34,27 @@ export default class MobileInkOverlay extends React.Component { } @action - initMobileInkOverlay(content: MobileInkBoxContent) { + initMobileInkOverlay(content: MobileInkOverlayContent) { const { width, height } = content; const scaledSize = this.initialSize(width ? width : 0, height ? height : 0); - this._width = scaledSize.width; - this._height = scaledSize.height; - this._scale = scaledSize.scale; + this._width = scaledSize.width * .5; + this._height = scaledSize.height * .5; + this._scale = .5; //scaledSize.scale; this._x = 300; // TODO: center on screen this._y = 25; // TODO: center on screen } + @action + updatePosition(content: UpdateMobileInkOverlayPosition) { + const { dx, dy, dsize } = content; + console.log(dx, dy, dsize); + } + drawStroke = (content: GestureContent) => { + // TODO: figure out why strokes drawn in corner of mobile interface dont get inserted + const { points, bounds } = content; + console.log("received points", points, bounds); const B = { right: (bounds.right * this._scale) + this._x, @@ -65,16 +80,66 @@ export default class MobileInkOverlay extends React.Component { ); } + @action + dragStart = (e: React.PointerEvent) => { + console.log("pointer down"); + document.removeEventListener("pointermove", this.dragging); + document.removeEventListener("pointerup", this.dragEnd); + document.addEventListener("pointermove", this.dragging); + document.addEventListener("pointerup", this.dragEnd); + + this._isDragging = true; + this._offsetX = e.pageX - this._mainCont.current!.getBoundingClientRect().left; + this._offsetY = e.pageY - this._mainCont.current!.getBoundingClientRect().top; + + e.preventDefault(); + e.stopPropagation(); + } + + @action + dragging = (e: PointerEvent) => { + const x = e.pageX - this._offsetX; + const y = e.pageY - this._offsetY; + + // TODO: don't allow drag over library? + this._x = Math.min(Math.max(x, 0), window.innerWidth - this._width); + this._y = Math.min(Math.max(y, 0), window.innerHeight - this._height); + + e.preventDefault(); + e.stopPropagation(); + } + + @action + dragEnd = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.dragging); + document.removeEventListener("pointerup", this.dragEnd); + + this._isDragging = false; + + e.preventDefault(); + e.stopPropagation(); + } + render() { + return ( -
+
+
+
+
+
+
); } } \ No newline at end of file diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss index e4cc919a5..8abe5a40d 100644 --- a/src/mobile/MobileInterface.scss +++ b/src/mobile/MobileInterface.scss @@ -1,4 +1,4 @@ -.mobileInterface-topButtons { +.mobileInterface-inkInterfaceButtons { position: absolute; display: flex; justify-content: space-between; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 4840ea374..b191b3afb 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -10,7 +10,7 @@ import { DocumentView } from '../client/views/nodes/DocumentView'; import { emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue } from '../Utils'; import { Transform } from '../client/util/Transform'; import { library } from '@fortawesome/fontawesome-svg-core'; -import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck } from '@fortawesome/free-solid-svg-icons'; +import { faPenNib, faHighlighter, faEraser, faMousePointer, faBreadSlice, faTrash, faCheck, faLongArrowAltLeft } from '@fortawesome/free-solid-svg-icons'; import { Scripting } from '../client/util/Scripting'; import { CollectionFreeFormView } from '../client/views/collections/collectionFreeForm/CollectionFreeFormView'; import GestureOverlay from '../client/views/GestureOverlay'; @@ -23,7 +23,7 @@ import { DateField } from '../new_fields/DateField'; import { GestureUtils } from '../pen-gestures/GestureUtils'; import { DocServer } from '../client/DocServer'; -library.add(faTrash, faCheck); +library.add(faLongArrowAltLeft); @observer export default class MobileInterface extends React.Component { @@ -68,8 +68,8 @@ export default class MobileInterface extends React.Component { InkingControl.Instance.switchTool(InkTool.Pen); this.drawingInk = true; - DocServer.Mobile.dispatchBoxTrigger({ - enableBox: true, + DocServer.Mobile.dispatchOverlayTrigger({ + enableOverlay: true, width: window.innerWidth, height: window.innerHeight }); @@ -112,12 +112,12 @@ export default class MobileInterface extends React.Component { return "hello"; } - onClick = (e: React.MouseEvent) => { + onBack = (e: React.MouseEvent) => { this.switchCurrentView("main"); InkingControl.Instance.switchTool(InkTool.None); // TODO: switch to previous tool - DocServer.Mobile.dispatchBoxTrigger({ - enableBox: false, + DocServer.Mobile.dispatchOverlayTrigger({ + enableOverlay: false, width: window.innerWidth, height: window.innerHeight }); @@ -126,37 +126,61 @@ export default class MobileInterface extends React.Component { this.drawingInk = false; } + shiftLeft = (e: React.MouseEvent) => { + DocServer.Mobile.dispatchOverlayPositionUpdate({ + dx: -10 + }); + } + + shiftRight = (e: React.MouseEvent) => { + DocServer.Mobile.dispatchOverlayPositionUpdate({ + dx: 10 + }); + } + @computed get inkContent() { + // TODO: support panning and zooming + // TODO: handle moving of ink strokes if (this.mainContainer) { return ( - -
- - +
+
+
+ +
+
+ +
+
+ + +
- window.innerHeight} - PanelWidth={() => window.innerWidth} - focus={emptyFunction} - isSelected={returnFalse} - select={emptyFunction} - active={returnFalse} - ContentScaling={returnOne} - whenActiveChanged={returnFalse} - ScreenToLocalTransform={Transform.Identity} - ruleProvider={undefined} - renderDepth={0} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined}> - - + + window.innerHeight} + PanelWidth={() => window.innerWidth} + focus={emptyFunction} + isSelected={returnFalse} + select={emptyFunction} + active={returnFalse} + ContentScaling={returnOne} + whenActiveChanged={returnFalse} + ScreenToLocalTransform={Transform.Identity} + ruleProvider={undefined} + renderDepth={0} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined}> + + +
); } } diff --git a/src/server/Message.ts b/src/server/Message.ts index 1958286df..064a19653 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -50,12 +50,18 @@ export interface GestureContent { readonly color?: string; } -export interface MobileInkBoxContent { - readonly enableBox: boolean; +export interface MobileInkOverlayContent { + readonly enableOverlay: boolean; readonly width?: number; readonly height?: number; } +export interface UpdateMobileInkOverlayPosition { + readonly dx?: number; + readonly dy?: number; + readonly dsize?: number; +} + export namespace MessageStore { export const Foo = new Message("Foo"); export const Bar = new Message("Bar"); @@ -65,8 +71,10 @@ export namespace MessageStore { export const GetDocument = new Message("Get Document"); export const DeleteAll = new Message("Delete All"); export const ConnectionTerminated = new Message("Connection Terminated"); + export const GesturePoints = new Message("Gesture Points"); - export const MobileInkBoxTrigger = new Message("Trigger Mobile Ink Box"); + export const MobileInkOverlayTrigger = new Message("Trigger Mobile Ink Overlay"); + export const UpdateMobileInkOverlayPosition = new Message("Update Mobile Ink Overlay Position"); export const GetRefField = new Message("Get Ref Field"); export const GetRefFields = new Message("Get Ref Fields"); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index 16e34bdfc..fe253400c 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -1,5 +1,5 @@ import { Utils } from "../../Utils"; -import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkBoxContent } from "../Message"; +import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent } from "../Message"; import { Client } from "../Client"; import { Socket } from "socket.io"; import { Database } from "../database"; @@ -55,7 +55,7 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); - Utils.AddServerHandler(socket, MessageStore.MobileInkBoxTrigger, content => processBoxTrigger(socket, content)); + Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); @@ -74,8 +74,8 @@ export namespace WebSocket { socket.broadcast.emit("receiveGesturePoints", content); } - function processBoxTrigger(socket: Socket, content: MobileInkBoxContent) { - socket.broadcast.emit("receiveBoxTrigger", content); + function processOverlayTrigger(socket: Socket, content: MobileInkOverlayContent) { + socket.broadcast.emit("receiveOverlayTrigger", content); } function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { -- cgit v1.2.3-70-g09d2 From 7249f3f2bd12794ca86775853aee700e398eeb00 Mon Sep 17 00:00:00 2001 From: vellichora Date: Sun, 2 Feb 2020 16:13:23 -0500 Subject: started creating upload from web on mobile --- src/client/DocServer.ts | 6 +- src/mobile/MobileInkOverlay.tsx | 15 ++--- src/mobile/MobileInterface.tsx | 72 ++++++++++++++++++++-- src/server/Message.ts | 4 +- src/server/Websocket/Websocket.ts | 7 ++- .../authentication/models/current_user_utils.ts | 14 ++++- 6 files changed, 99 insertions(+), 19 deletions(-) (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index b20cd3521..c03764471 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPosition } from "./../server/Message"; +import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from "./../server/Message"; import { Opt, Doc } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -77,7 +77,7 @@ export namespace DocServer { Utils.Emit(_socket, MessageStore.MobileInkOverlayTrigger, content); } - export function dispatchOverlayPositionUpdate(content: UpdateMobileInkOverlayPosition) { + export function dispatchOverlayPositionUpdate(content: UpdateMobileInkOverlayPositionContent) { Utils.Emit(_socket, MessageStore.UpdateMobileInkOverlayPosition, content); } @@ -113,7 +113,7 @@ export namespace DocServer { GestureOverlay.Instance.enableMobileInkOverlay(content); MobileInkOverlay.Instance.initMobileInkOverlay(content); }); - _socket.addEventListener("updateMobileOverlayPosition", (content: UpdateMobileInkOverlayPosition) => { + _socket.addEventListener("receiveUpdateOverlayPosition", (content: UpdateMobileInkOverlayPositionContent) => { MobileInkOverlay.Instance.updatePosition(content); }); } diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 5efc7b83a..600e8a91b 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,6 +1,6 @@ import React = require('react'); import { observer } from "mobx-react"; -import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPosition } from "../server/Message"; +import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPositionContent } from "../server/Message"; import { observable, action } from "mobx"; import { GestureUtils } from "../pen-gestures/GestureUtils"; import "./MobileInkOverlay.scss"; @@ -37,17 +37,19 @@ export default class MobileInkOverlay extends React.Component { initMobileInkOverlay(content: MobileInkOverlayContent) { const { width, height } = content; const scaledSize = this.initialSize(width ? width : 0, height ? height : 0); - this._width = scaledSize.width * .5; - this._height = scaledSize.height * .5; - this._scale = .5; //scaledSize.scale; + this._width = scaledSize.width * .8; + this._height = scaledSize.height * .8; + this._scale = .8; //scaledSize.scale; this._x = 300; // TODO: center on screen this._y = 25; // TODO: center on screen } @action - updatePosition(content: UpdateMobileInkOverlayPosition) { + updatePosition(content: UpdateMobileInkOverlayPositionContent) { const { dx, dy, dsize } = content; - console.log(dx, dy, dsize); + if (dx) this._x += dx; + if (dy) this._y += dy; + // TODO: scale dsize } drawStroke = (content: GestureContent) => { @@ -82,7 +84,6 @@ export default class MobileInkOverlay extends React.Component { @action dragStart = (e: React.PointerEvent) => { - console.log("pointer down"); document.removeEventListener("pointermove", this.dragging); document.removeEventListener("pointerup", this.dragEnd); document.addEventListener("pointermove", this.dragging); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index b191b3afb..03bcbca80 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -30,12 +30,15 @@ export default class MobileInterface extends React.Component { @observable static Instance: MobileInterface; @computed private get userDoc() { return CurrentUserUtils.UserDocument; } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } - @observable private currentView: "main" | "ink" | "library" = "main"; + @observable private currentView: "main" | "ink" | "upload" = "main"; private mainDoc = CurrentUserUtils.setupMobileDoc(this.userDoc); + private inkDoc?: Doc; public drawingInk: boolean = false; + private uploadDoc?: Doc; + constructor(props: Readonly<{}>) { super(props); MobileInterface.Instance = this; @@ -52,7 +55,7 @@ export default class MobileInterface extends React.Component { } @action - switchCurrentView = (view: "main" | "ink" | "library") => { + switchCurrentView = (view: "main" | "ink" | "upload") => { this.currentView = view; if (this.userDoc) { @@ -76,6 +79,11 @@ export default class MobileInterface extends React.Component { break; } + case "upload": { + this.uploadDoc = CurrentUserUtils.setupMobileUploadDoc(this.userDoc); + this.userDoc.activeMobile = this.uploadDoc; + + } } } } @@ -127,15 +135,20 @@ export default class MobileInterface extends React.Component { } shiftLeft = (e: React.MouseEvent) => { + console.log("shift left!"); DocServer.Mobile.dispatchOverlayPositionUpdate({ dx: -10 }); + e.preventDefault(); + e.stopPropagation(); } shiftRight = (e: React.MouseEvent) => { DocServer.Mobile.dispatchOverlayPositionUpdate({ dx: 10 }); + e.preventDefault(); + e.stopPropagation(); } @computed @@ -147,7 +160,7 @@ export default class MobileInterface extends React.Component {
- +
@@ -185,8 +198,57 @@ export default class MobileInterface extends React.Component { } } + upload = () => { + + } + + @computed + get uploadContent() { + if (this.mainContainer) { + return ( +
+
+
+ +
+
+ +
+
+ window.screen.width} + PanelHeight={() => window.screen.height} + renderDepth={0} + focus={emptyFunction} + backgroundColor={returnEmptyString} + parentActive={returnTrue} + whenActiveChanged={emptyFunction} + bringToFront={emptyFunction} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined} + zoomToScale={emptyFunction} + getScale={returnOne}> + +
+ ); + } + } + render() { - const content = this.currentView === "main" ? this.mainContent : this.currentView === "ink" ? this.inkContent : <>; + const content = this.currentView === "main" ? this.mainContent : + this.currentView === "ink" ? this.inkContent : + this.currentView === "upload" ? this.uploadContent : <>; return (
{content} @@ -195,4 +257,4 @@ export default class MobileInterface extends React.Component { } } -Scripting.addGlobal(function switchMobileView(view: "main" | "ink" | "library") { return MobileInterface.Instance.switchCurrentView(view); }); +Scripting.addGlobal(function switchMobileView(view: "main" | "ink" | "upload") { return MobileInterface.Instance.switchCurrentView(view); }); diff --git a/src/server/Message.ts b/src/server/Message.ts index 064a19653..236df3f3c 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -56,7 +56,7 @@ export interface MobileInkOverlayContent { readonly height?: number; } -export interface UpdateMobileInkOverlayPosition { +export interface UpdateMobileInkOverlayPositionContent { readonly dx?: number; readonly dy?: number; readonly dsize?: number; @@ -74,7 +74,7 @@ export namespace MessageStore { export const GesturePoints = new Message("Gesture Points"); export const MobileInkOverlayTrigger = new Message("Trigger Mobile Ink Overlay"); - export const UpdateMobileInkOverlayPosition = new Message("Update Mobile Ink Overlay Position"); + export const UpdateMobileInkOverlayPosition = new Message("Update Mobile Ink Overlay Position"); export const GetRefField = new Message("Get Ref Field"); export const GetRefFields = new Message("Get Ref Fields"); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index fe253400c..77816c897 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -1,5 +1,5 @@ import { Utils } from "../../Utils"; -import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent } from "../Message"; +import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from "../Message"; import { Client } from "../Client"; import { Socket } from "socket.io"; import { Database } from "../database"; @@ -56,6 +56,7 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); + Utils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); @@ -78,6 +79,10 @@ export namespace WebSocket { socket.broadcast.emit("receiveOverlayTrigger", content); } + function processUpdateOverlayPosition(socket: Socket, content: UpdateMobileInkOverlayPositionContent) { + socket.broadcast.emit("receiveUpdateOverlayPosition", content); + } + function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { const { ProjectCredentials } = GoogleCredentialsLoader; switch (query.type) { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 98092ddfe..82bed76f7 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -101,7 +101,8 @@ export class CurrentUserUtils { { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, - { title: "draw", icon: "mouse-pointer", click: 'switchMobileView("ink");', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, + { title: "draw", icon: "pen-nib", click: 'switchMobileView("ink");', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, + { title: "upload", icon: "upload", click: 'switchMobileView("upload");', backgroundColor: "orange" }, ]; 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, @@ -144,6 +145,17 @@ export class CurrentUserUtils { return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white" }); } + static setupMobileUploadDoc(userDoc: Doc) { + console.log("setup mobile upload", window.innerWidth, window.innerHeight); + const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled", ignoreClick: true }); + const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload", backgroundColor: "pink" }); + return Docs.Create.StackingDocument([webDoc, uploadDoc], { + title: "Mobile Upload", backgroundColor: "white", + columnWidth: window.innerWidth, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", autoHeight: true, yMargin: 5, + width: window.innerWidth, height: window.innerHeight + }); + } + // 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 setupToolsPanel(sidebarContainer: Doc, doc: Doc) { // setup a masonry view of all he creators -- cgit v1.2.3-70-g09d2 From 28efd6f2b5b79d1f25fa66e5d9f69d77a7594fee Mon Sep 17 00:00:00 2001 From: vellichora Date: Sat, 8 Feb 2020 20:48:51 -0500 Subject: refactored mobile interface so that current views are created via scripting --- src/client/views/nodes/WebBox.tsx | 6 +- src/mobile/ImageUpload.tsx | 10 +- src/mobile/MobileInkOverlay.tsx | 6 +- src/mobile/MobileInterface.tsx | 115 +++++++++++++-------- .../authentication/models/current_user_utils.ts | 13 ++- 5 files changed, 92 insertions(+), 58 deletions(-) (limited to 'src/server') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index b35ea0bb0..0b23c3bec 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -182,9 +182,11 @@ export class WebBox extends DocAnnotatableComponent {view}
; - const frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; + const decInteracting = DocumentDecorations.Instance && DocumentDecorations.Instance.Interacting; - const classname = "webBox-cont" + (this.props.isSelected() && InkingControl.Instance.selectedTool === InkTool.None && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); + const frozen = !this.props.isSelected() || decInteracting; + + const classname = "webBox-cont" + (this.props.isSelected() && InkingControl.Instance.selectedTool === InkTool.None && !decInteracting ? "-interactive" : ""); return ( <>
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 0b0280519..3304e8e22 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -13,6 +13,7 @@ import { observable } from 'mobx'; import { Utils } from '../Utils'; import MobileInterface from './MobileInterface'; import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; +import { Scripting } from '../client/util/Scripting'; @@ -27,12 +28,11 @@ const inputRef = React.createRef(); @observer class Uploader extends React.Component { - @observable - error: string = ""; - @observable - status: string = ""; + @observable error: string = ""; + @observable status: string = ""; onClick = async () => { + console.log("uploader click"); try { this.status = "initializing protos"; await Docs.Prototypes.initialize(); @@ -105,6 +105,8 @@ class Uploader extends React.Component { } +// Scripting.addGlobal(function uploadImageMobile() { return Uploader.onClick(); }); + // DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload"); (async () => { diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 600e8a91b..6b65aa436 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -37,9 +37,9 @@ export default class MobileInkOverlay extends React.Component { initMobileInkOverlay(content: MobileInkOverlayContent) { const { width, height } = content; const scaledSize = this.initialSize(width ? width : 0, height ? height : 0); - this._width = scaledSize.width * .8; - this._height = scaledSize.height * .8; - this._scale = .8; //scaledSize.scale; + this._width = scaledSize.width; + this._height = scaledSize.height; + this._scale = scaledSize.scale; //scaledSize.scale; this._x = 300; // TODO: center on screen this._y = 25; // TODO: center on screen } diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 03bcbca80..665d9a168 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -30,14 +30,14 @@ export default class MobileInterface extends React.Component { @observable static Instance: MobileInterface; @computed private get userDoc() { return CurrentUserUtils.UserDocument; } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } - @observable private currentView: "main" | "ink" | "upload" = "main"; + // @observable private currentView: "main" | "ink" | "upload" = "main"; + private mainDoc: Doc = CurrentUserUtils.setupMobileDoc(this.userDoc); + @observable private renderView?: () => JSX.Element; - private mainDoc = CurrentUserUtils.setupMobileDoc(this.userDoc); - - private inkDoc?: Doc; + // private inkDoc?: Doc; public drawingInk: boolean = false; - private uploadDoc?: Doc; + // private uploadDoc?: Doc; constructor(props: Readonly<{}>) { super(props); @@ -55,41 +55,63 @@ export default class MobileInterface extends React.Component { } @action - switchCurrentView = (view: "main" | "ink" | "upload") => { - this.currentView = view; + switchCurrentView = (doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) => { + if (!this.userDoc) return; - if (this.userDoc) { - switch (view) { - case "main": { - // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); - this.userDoc.activeMobile = this.mainDoc; - break; - } - case "ink": { - this.inkDoc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); - this.userDoc.activeMobile = this.inkDoc; - InkingControl.Instance.switchTool(InkTool.Pen); - this.drawingInk = true; + this.userDoc.activeMobile = doc(this.userDoc); + onSwitch && onSwitch(); - DocServer.Mobile.dispatchOverlayTrigger({ - enableOverlay: true, - width: window.innerWidth, - height: window.innerHeight - }); + this.renderView = renderView; + console.log("switching current view", renderView); + } - break; - } - case "upload": { - this.uploadDoc = CurrentUserUtils.setupMobileUploadDoc(this.userDoc); - this.userDoc.activeMobile = this.uploadDoc; + onSwitchInking = () => { + InkingControl.Instance.switchTool(InkTool.Pen); + MobileInterface.Instance.drawingInk = true; - } - } - } + DocServer.Mobile.dispatchOverlayTrigger({ + enableOverlay: true, + width: window.innerWidth, + height: window.innerHeight + }); } - @computed - get mainContent() { + // @action + // switchCurrentView = (view: "main" | "ink" | "upload") => { + // this.currentView = view; + + // if (this.userDoc) { + // switch (view) { + // case "main": { + // // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); + // this.userDoc.activeMobile = this.mainDoc; + // break; + // } + // case "ink": { + // this.inkDoc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); + // this.userDoc.activeMobile = this.inkDoc; + // InkingControl.Instance.switchTool(InkTool.Pen); + // this.drawingInk = true; + + // DocServer.Mobile.dispatchOverlayTrigger({ + // enableOverlay: true, + // width: window.innerWidth, + // height: window.innerHeight + // }); + + // break; + // } + // case "upload": { + // this.uploadDoc = CurrentUserUtils.setupMobileUploadDoc(this.userDoc); + // this.userDoc.activeMobile = this.uploadDoc; + + // } + // } + // } + // } + + renderDefaultContent = () => { + console.log("rendering default content"); if (this.mainContainer) { return { - this.switchCurrentView("main"); + this.switchCurrentView((userDoc: Doc) => this.mainDoc); InkingControl.Instance.switchTool(InkTool.None); // TODO: switch to previous tool DocServer.Mobile.dispatchOverlayTrigger({ @@ -130,7 +152,7 @@ export default class MobileInterface extends React.Component { height: window.innerHeight }); - this.inkDoc = undefined; + // this.inkDoc = undefined; this.drawingInk = false; } @@ -151,8 +173,8 @@ export default class MobileInterface extends React.Component { e.stopPropagation(); } - @computed - get inkContent() { + renderInkingContent = () => { + console.log("rendering inking content"); // TODO: support panning and zooming // TODO: handle moving of ink strokes if (this.mainContainer) { @@ -202,8 +224,7 @@ export default class MobileInterface extends React.Component { } - @computed - get uploadContent() { + renderUploadContent() { if (this.mainContainer) { return (
@@ -246,15 +267,19 @@ 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 : <>; + // const content = this.currentView === "main" ? this.mainContent : + // this.currentView === "ink" ? this.inkContent : + // this.currentView === "upload" ? this.uploadContent : <>; return (
- {content} + {this.renderView ? this.renderView() : this.renderDefaultContent()}
); } } -Scripting.addGlobal(function switchMobileView(view: "main" | "ink" | "upload") { return MobileInterface.Instance.switchCurrentView(view); }); +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 renderMobileUpload() { return MobileInterface.Instance.renderUploadContent(); }); + diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 82bed76f7..817cf40b1 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -14,6 +14,7 @@ import { Utils } from "../../../Utils"; import { nullAudio } from "../../../new_fields/URLField"; import { DragManager } from "../../../client/util/DragManager"; import { InkingControl } from "../../../client/views/InkingControl"; +import { Scripting } from "../../../client/util/Scripting"; export class CurrentUserUtils { private static curr_id: string; @@ -101,8 +102,9 @@ export class CurrentUserUtils { { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, - { title: "draw", icon: "pen-nib", click: 'switchMobileView("ink");', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, - { title: "upload", icon: "upload", click: 'switchMobileView("upload");', backgroundColor: "orange" }, + { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, + { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload);', backgroundColor: "orange" }, + { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, ]; 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, @@ -147,7 +149,7 @@ export class CurrentUserUtils { static setupMobileUploadDoc(userDoc: Doc) { console.log("setup mobile upload", window.innerWidth, window.innerHeight); - const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled", ignoreClick: true }); + const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" }); const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload", backgroundColor: "pink" }); return Docs.Create.StackingDocument([webDoc, uploadDoc], { title: "Mobile Upload", backgroundColor: "white", @@ -388,4 +390,7 @@ export class CurrentUserUtils { }; return recurs([] as Attribute[], schema ? schema.rootAttributeGroup : undefined); } -} \ No newline at end of file +} + +Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); }); +Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); }); \ No newline at end of file -- cgit v1.2.3-70-g09d2 From e8fcbbf57b2a2f443d9c280ce10558cf9d51c632 Mon Sep 17 00:00:00 2001 From: vellichora Date: Sun, 9 Feb 2020 17:11:24 -0500 Subject: can upload collection from mobile to desktop --- src/client/DocServer.ts | 9 +- src/client/util/DragManager.ts | 2 +- .../collections/CollectionMasonryViewFieldRow.tsx | 1 + .../views/collections/CollectionStackingView.tsx | 2 + .../CollectionStackingViewFieldColumn.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../views/collections/CollectionViewChromes.tsx | 1 + src/mobile/ImageUpload.tsx | 1 + src/mobile/MobileInkOverlay.tsx | 53 +++++++- src/mobile/MobileInterface.scss | 8 ++ src/mobile/MobileInterface.tsx | 150 ++++++++++++--------- src/server/ApiManagers/UploadManager.ts | 1 + src/server/Message.ts | 6 + src/server/Websocket/Websocket.ts | 7 +- .../authentication/models/current_user_utils.ts | 21 +-- src/server/server_Initialization.ts | 24 ++-- 17 files changed, 195 insertions(+), 96 deletions(-) (limited to 'src/server') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index c03764471..e09251855 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from "./../server/Message"; +import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message"; import { Opt, Doc } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -81,6 +81,10 @@ export namespace DocServer { Utils.Emit(_socket, MessageStore.UpdateMobileInkOverlayPosition, content); } + export function dispatchMobileDocumentUpload(content: MobileDocumentUploadContent) { + Utils.Emit(_socket, MessageStore.MobileDocumentUpload, content); + } + } export function init(protocol: string, hostname: string, port: number, identifier: string) { @@ -116,6 +120,9 @@ export namespace DocServer { _socket.addEventListener("receiveUpdateOverlayPosition", (content: UpdateMobileInkOverlayPositionContent) => { MobileInkOverlay.Instance.updatePosition(content); }); + _socket.addEventListener("receiveMobileDocumentUpload", (content: MobileDocumentUploadContent) => { + MobileInkOverlay.Instance.uploadDocument(content); + }); } function errorFunc(): never { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index df2f5fe3c..0bb8b531d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -179,7 +179,7 @@ export namespace DragManager { ); } element.dataset.canDrop = "true"; - const handler = (e: Event) => dropFunc(e, (e as CustomEvent).detail); + const handler = (e: Event) => { console.log("drop target reveied docs"); dropFunc(e, (e as CustomEvent).detail); }; element.addEventListener("dashOnDrop", handler); return () => { element.removeEventListener("dashOnDrop", handler); diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 80752303c..26e0cc35a 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -73,6 +73,7 @@ export class CollectionMasonryViewFieldRow extends React.Component { + console.log("masronry row drop"); this._createAliasSelected = false; if (de.complete.docDragData) { (this.props.parent.Document.dropConverter instanceof ScriptField) && diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 992820fc7..83c90810e 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -240,6 +240,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { + console.log("DROP STACKIN G2"); const where = [de.x, de.y]; let targInd = -1; let plusOne = 0; @@ -270,6 +271,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @undoBatch @action onDrop = async (e: React.DragEvent): Promise => { + console.log("DROP STACKING"); const where = [e.clientX, e.clientY]; let targInd = -1; this._docXfs.map((cd, i) => { diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 39b4e4e1d..65c4b3195 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -57,6 +57,7 @@ export class CollectionStackingViewFieldColumn extends React.Component { + console.log("column drop stacking"); this._createAliasSelected = false; if (de.complete.docDragData) { const key = StrCast(this.props.parent.props.Document.sectionFilter); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index e94f24f2c..b35af2314 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -6,7 +6,7 @@ import { Id } from "../../../new_fields/FieldSymbols"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; -import { Cast } from "../../../new_fields/Types"; +import { Cast, StrCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 88023783b..1d399e26f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -138,7 +138,7 @@ export class CollectionView extends Touchable { let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); - ContextMenu.Instance.clearItems(); + ContextMenu.Instance && ContextMenu.Instance.clearItems(); if (index !== -1) { value.splice(index, 1); return true; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index a870b6043..01dc21f95 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -231,6 +231,7 @@ export class CollectionViewBaseChrome extends React.Component { + console.log("toggle collapse"); this.props.CollectionView.props.Document.chromeStatus = this.props.CollectionView.props.Document.chromeStatus === "enabled" ? "collapsed" : "enabled"; if (this.props.collapse) { this.props.collapse(this.props.CollectionView.props.Document.chromeStatus !== "enabled"); diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 3304e8e22..10bd78075 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -47,6 +47,7 @@ class Uploader extends React.Component { const upload = window.location.origin + "/upload"; this.status = "uploading image"; + console.log("uploading image", formData); const res = await fetch(upload, { method: 'POST', body: formData diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 6b65aa436..ed4cca5b9 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -1,9 +1,13 @@ import React = require('react'); import { observer } from "mobx-react"; -import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPositionContent } from "../server/Message"; +import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "../server/Message"; import { observable, action } from "mobx"; import { GestureUtils } from "../pen-gestures/GestureUtils"; import "./MobileInkOverlay.scss"; +import { StrCast } from '../new_fields/Types'; +import { DragManager } from "../client/util/DragManager"; +import { DocServer } from '../client/DocServer'; +import { Doc } from '../new_fields/Doc'; @observer @@ -67,7 +71,7 @@ export default class MobileInkOverlay extends React.Component { height: bounds.height * this._scale, }; - const target = document.elementFromPoint(points[0].X, points[0].Y); + const target = document.elementFromPoint(this._x + 10, this._y + 10); target?.dispatchEvent( new CustomEvent("dashOnGesture", { @@ -82,6 +86,43 @@ export default class MobileInkOverlay extends React.Component { ); } + uploadDocument = async (content: MobileDocumentUploadContent) => { + const { docId } = content; + console.log("receive upload document id", docId); + const doc = await DocServer.GetRefField(docId); + + if (doc && doc instanceof Doc) { + console.log("parsed upload document into doc", StrCast(doc.proto!.title)); + + const target = document.elementFromPoint(this._x + 10, this._y + 10); + console.log("the target is", target); + + const dragData = new DragManager.DocumentDragData([doc]); + const complete = new DragManager.DragCompleteEvent(false, dragData); + console.log("the drag data is", dragData); + + if (target) { + target.dispatchEvent( + new CustomEvent("dashOnDrop", + { + bubbles: true, + detail: { + x: this._x, + y: this._y, + complete: complete, + altKey: false, + metaKey: false, + ctrlKey: false + } + } + ) + ); + } else { + alert("TARGET IS UNDEFINED"); + } + } + } + @action dragStart = (e: React.PointerEvent) => { document.removeEventListener("pointermove", this.dragging); @@ -132,15 +173,17 @@ export default class MobileInkOverlay extends React.Component { transform: `translate(${this._x}px, ${this._y}px)`, zIndex: 30000, pointerEvents: "none", - borderStyle: this._isDragging ? "solid" : "dashed" - }} + borderStyle: this._isDragging ? "solid" : "dashed", + backgroundColor: "rgba(255, 0, 0, 0.3)" + } + } ref={this._mainCont} >
-
+
); } } \ No newline at end of file diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss index 8abe5a40d..8b0ebcd53 100644 --- a/src/mobile/MobileInterface.scss +++ b/src/mobile/MobileInterface.scss @@ -1,7 +1,15 @@ .mobileInterface-inkInterfaceButtons { position: absolute; + top: -50px; display: flex; justify-content: space-between; width: 100%; z-index: 9999; + height: 50px; +} + +.mobileInterface-container { + height: calc(100% - 50px); + margin-top: 50px; + position: relative; } \ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 665d9a168..a1ef0a5d1 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -22,6 +22,18 @@ import { SelectionManager } from '../client/util/SelectionManager'; import { DateField } from '../new_fields/DateField'; import { GestureUtils } from '../pen-gestures/GestureUtils'; import { DocServer } from '../client/DocServer'; +import { DocumentDecorations } from '../client/views/DocumentDecorations'; +import { OverlayView } from '../client/views/OverlayView'; +import { DictationOverlay } from '../client/views/DictationOverlay'; +import SharingManager from '../client/util/SharingManager'; +import { PreviewCursor } from '../client/views/PreviewCursor'; +import { ContextMenu } from '../client/views/ContextMenu'; +import { RadialMenu } from '../client/views/nodes/RadialMenu'; +import PDFMenu from '../client/views/pdf/PDFMenu'; +import MarqueeOptionsMenu from '../client/views/collections/collectionFreeForm/MarqueeOptionsMenu'; +import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationManager'; +import { listSpec } from '../new_fields/Schema'; +import { Id } from '../new_fields/FieldSymbols'; library.add(faLongArrowAltLeft); @@ -31,7 +43,7 @@ export default class MobileInterface extends React.Component { @computed private get userDoc() { return CurrentUserUtils.UserDocument; } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; } // @observable private currentView: "main" | "ink" | "upload" = "main"; - private mainDoc: Doc = CurrentUserUtils.setupMobileDoc(this.userDoc); + private mainDoc: any = CurrentUserUtils.setupMobileDoc(this.userDoc); @observable private renderView?: () => JSX.Element; // private inkDoc?: Doc; @@ -49,7 +61,6 @@ export default class MobileInterface extends React.Component { library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer]); if (this.userDoc && !this.mainContainer) { - // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); this.userDoc.activeMobile = this.mainDoc; } } @@ -76,48 +87,22 @@ export default class MobileInterface extends React.Component { }); } - // @action - // switchCurrentView = (view: "main" | "ink" | "upload") => { - // this.currentView = view; - - // if (this.userDoc) { - // switch (view) { - // case "main": { - // // const doc = CurrentUserUtils.setupMobileDoc(this.userDoc); - // this.userDoc.activeMobile = this.mainDoc; - // break; - // } - // case "ink": { - // this.inkDoc = CurrentUserUtils.setupMobileInkingDoc(this.userDoc); - // this.userDoc.activeMobile = this.inkDoc; - // InkingControl.Instance.switchTool(InkTool.Pen); - // this.drawingInk = true; - - // DocServer.Mobile.dispatchOverlayTrigger({ - // enableOverlay: true, - // width: window.innerWidth, - // height: window.innerHeight - // }); - - // break; - // } - // case "upload": { - // this.uploadDoc = CurrentUserUtils.setupMobileUploadDoc(this.userDoc); - // this.userDoc.activeMobile = this.uploadDoc; - - // } - // } - // } - // } + onSwitchUpload = () => { + DocServer.Mobile.dispatchOverlayTrigger({ + enableOverlay: true, + width: 100, + height: 100 + }); + } renderDefaultContent = () => { - console.log("rendering default content"); + console.log("rendering default content", this.mainContainer); if (this.mainContainer) { return { console.log("want to add doc to default content", StrCast(doc.title)); return false; }} addDocTab={returnFalse} pinToPres={emptyFunction} removeDocument={undefined} @@ -192,42 +177,54 @@ export default class MobileInterface extends React.Component {
- - window.innerHeight} - PanelWidth={() => window.innerWidth} - focus={emptyFunction} - isSelected={returnFalse} - select={emptyFunction} - active={returnFalse} - ContentScaling={returnOne} - whenActiveChanged={returnFalse} - ScreenToLocalTransform={Transform.Identity} - ruleProvider={undefined} - renderDepth={0} - ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined}> - - + window.innerHeight} + PanelWidth={() => window.innerWidth} + focus={emptyFunction} + isSelected={returnFalse} + select={emptyFunction} + active={returnFalse} + ContentScaling={returnOne} + whenActiveChanged={returnFalse} + ScreenToLocalTransform={Transform.Identity} + ruleProvider={undefined} + renderDepth={0} + ContainingCollectionView={undefined} + ContainingCollectionDoc={undefined}> +
); } } - upload = () => { + upload = async (e: React.MouseEvent) => { + if (this.mainContainer) { + const data = Cast(this.mainContainer.data, listSpec(Doc)); + if (data) { + const uploadDoc = await data[1]; // TODO: ensure this is the collection to upload + console.log("UPLOADING DOCUMENT FROM MOBILE", uploadDoc[Id], StrCast(uploadDoc.proto!.title)); + if (uploadDoc) { + DocServer.Mobile.dispatchMobileDocumentUpload({ + docId: uploadDoc[Id] + }); + } + } + } + e.stopPropagation(); + e.preventDefault(); } renderUploadContent() { if (this.mainContainer) { return ( -
+
@@ -240,7 +237,7 @@ export default class MobileInterface extends React.Component { Document={this.mainContainer} DataDoc={undefined} LibraryPath={emptyPath} - addDocument={returnFalse} + addDocument={(doc: Doc) => { console.log("want to add doc", StrCast(doc.title)); return false; }} addDocTab={returnFalse} pinToPres={emptyFunction} removeDocument={undefined} @@ -266,13 +263,35 @@ export default class MobileInterface extends React.Component { } } + onDragOver = (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + } + render() { // const content = this.currentView === "main" ? this.mainContent : // this.currentView === "ink" ? this.inkContent : // this.currentView === "upload" ? this.uploadContent : <>; return ( -
- {this.renderView ? this.renderView() : this.renderDefaultContent()} +
+ {/* + + {this.renderView ? this.renderView() : this.renderDefaultContent()} + */} + + {/* + + */} + + + {this.renderView ? this.renderView() : this.renderDefaultContent()} + + + {/* */} + + {/* + + */}
); } @@ -281,5 +300,6 @@ export default class MobileInterface extends React.Component { Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); }); Scripting.addGlobal(function 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(); }); diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 74f45ae62..e76d9b7a2 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -42,6 +42,7 @@ export default class UploadManager extends ApiManager { method: Method.POST, subscription: "/upload", secureHandler: async ({ req, res }) => { + console.log("/upload register"); const form = new formidable.IncomingForm(); form.uploadDir = pathToDirectory(Directory.parsed_files); form.keepExtensions = true; diff --git a/src/server/Message.ts b/src/server/Message.ts index 236df3f3c..c23a2f0a8 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -1,5 +1,6 @@ import { Utils } from "../Utils"; import { Point } from "../pen-gestures/ndollar"; +import { Doc } from "../new_fields/Doc"; export class Message { private _name: string; @@ -62,6 +63,10 @@ export interface UpdateMobileInkOverlayPositionContent { readonly dsize?: number; } +export interface MobileDocumentUploadContent { + readonly docId: string; +} + export namespace MessageStore { export const Foo = new Message("Foo"); export const Bar = new Message("Bar"); @@ -75,6 +80,7 @@ export namespace MessageStore { export const GesturePoints = new Message("Gesture Points"); export const MobileInkOverlayTrigger = new Message("Trigger Mobile Ink Overlay"); export const UpdateMobileInkOverlayPosition = new Message("Update Mobile Ink Overlay Position"); + export const MobileDocumentUpload = new Message("Upload Document From Mobile"); export const GetRefField = new Message("Get Ref Field"); export const GetRefFields = new Message("Get Ref Fields"); diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts index 77816c897..798bdae67 100644 --- a/src/server/Websocket/Websocket.ts +++ b/src/server/Websocket/Websocket.ts @@ -1,5 +1,5 @@ import { Utils } from "../../Utils"; -import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent } from "../Message"; +import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "../Message"; import { Client } from "../Client"; import { Socket } from "socket.io"; import { Database } from "../database"; @@ -57,6 +57,7 @@ export namespace WebSocket { Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); Utils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); + Utils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); @@ -83,6 +84,10 @@ export namespace WebSocket { socket.broadcast.emit("receiveUpdateOverlayPosition", content); } + function processMobileDocumentUpload(socket: Socket, content: MobileDocumentUploadContent) { + socket.broadcast.emit("receiveMobileDocumentUpload", content); + } + function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { const { ProjectCredentials } = GoogleCredentialsLoader; switch (query.type) { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 817cf40b1..3e5953ac1 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -103,7 +103,7 @@ export class CurrentUserUtils { { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, - { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload);', backgroundColor: "orange" }, + { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" }, { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, ]; return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({ @@ -138,7 +138,9 @@ export class CurrentUserUtils { } static setupMobileDoc(userDoc: Doc) { - return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), { + const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" }); + + return userDoc.activeMoble ?? Docs.Create.MasonryDocument([webDoc, ...CurrentUserUtils.setupMobileButtons(userDoc)], { columnWidth: 100, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", autoHeight: true, yMargin: 5 }); } @@ -148,13 +150,14 @@ export class CurrentUserUtils { } static setupMobileUploadDoc(userDoc: Doc) { - console.log("setup mobile upload", window.innerWidth, window.innerHeight); - const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" }); - const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload", backgroundColor: "pink" }); - return Docs.Create.StackingDocument([webDoc, uploadDoc], { - title: "Mobile Upload", backgroundColor: "white", - columnWidth: window.innerWidth, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", autoHeight: true, yMargin: 5, - width: window.innerWidth, height: window.innerHeight + const webDoc = Docs.Create.WebDocument("https://yahoo.com", { title: "Upload Images From the Web", chromeStatus: "enabled" }); + const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload Collection", backgroundColor: "pink" }); + console.log("window size", window.innerWidth, window.innerHeight); + // return Docs.Create.StackingDocument([webDoc, uploadDoc], { + // columnWidth: window.innerWidth, //ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "Mobile Upload", autoHeight: true, yMargin: 5 + // }); + return Docs.Create.StackingDocument([webDoc, uploadDoc], {//...CurrentUserUtils.setupMobileButtons(userDoc)], { + columnWidth: 100, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 30 }); } diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index cbe070293..5f1ecc733 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -42,18 +42,18 @@ export default async function InitializeServer(routeSetter: RouteSetter) { } }; app.use(cors(corsOptions)); - app.use("*", ({ user, originalUrl }, res, next) => { - if (user && !originalUrl.includes("Heartbeat")) { - const userEmail = (user as any).email; - if (userEmail) { - timeMap[userEmail] = Date.now(); - } - } - if (!user && originalUrl === "/") { - return res.redirect("/login"); - } - next(); - }); + // app.use("*", ({ user, originalUrl }, res, next) => { + // if (user && !originalUrl.includes("Heartbeat")) { + // const userEmail = (user as any).email; + // if (userEmail) { + // timeMap[userEmail] = Date.now(); + // } + // } + // if (!user && originalUrl === "/") { + // return res.redirect("/login"); + // } + // next(); + // }); app.use(wdm(compiler, { publicPath: config.output.publicPath })); app.use(whm(compiler)); -- cgit v1.2.3-70-g09d2 From bede55e2f8504a4b45c3adb96d6ba2d13c17b96f Mon Sep 17 00:00:00 2001 From: vellichora Date: Sun, 9 Feb 2020 17:43:54 -0500 Subject: option to upload as collection for mobile --- src/mobile/MobileInkOverlay.tsx | 15 +++++++++++---- src/mobile/MobileInterface.tsx | 8 +++++--- src/server/Message.ts | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/server') diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index ed4cca5b9..9f810424a 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -4,10 +4,11 @@ import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPosition import { observable, action } from "mobx"; import { GestureUtils } from "../pen-gestures/GestureUtils"; import "./MobileInkOverlay.scss"; -import { StrCast } from '../new_fields/Types'; +import { StrCast, Cast } from '../new_fields/Types'; import { DragManager } from "../client/util/DragManager"; import { DocServer } from '../client/DocServer'; -import { Doc } from '../new_fields/Doc'; +import { Doc, DocListCastAsync } from '../new_fields/Doc'; +import { listSpec } from '../new_fields/Schema'; @observer @@ -87,7 +88,7 @@ export default class MobileInkOverlay extends React.Component { } uploadDocument = async (content: MobileDocumentUploadContent) => { - const { docId } = content; + const { docId, asCollection } = content; console.log("receive upload document id", docId); const doc = await DocServer.GetRefField(docId); @@ -97,7 +98,13 @@ export default class MobileInkOverlay extends React.Component { const target = document.elementFromPoint(this._x + 10, this._y + 10); console.log("the target is", target); - const dragData = new DragManager.DocumentDragData([doc]); + let uploadDocs = [doc]; + if (!asCollection) { + const children = await DocListCastAsync(doc.data); + console.log("uploading children", children); + uploadDocs = children ? children : []; + } + const dragData = new DragManager.DocumentDragData(uploadDocs); const complete = new DragManager.DragCompleteEvent(false, dragData); console.log("the drag data is", dragData); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index a1ef0a5d1..e21258c62 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -203,7 +203,7 @@ export default class MobileInterface extends React.Component { } } - upload = async (e: React.MouseEvent) => { + upload = async (e: React.MouseEvent, asCollection: boolean) => { if (this.mainContainer) { const data = Cast(this.mainContainer.data, listSpec(Doc)); if (data) { @@ -212,7 +212,8 @@ export default class MobileInterface extends React.Component { console.log("UPLOADING DOCUMENT FROM MOBILE", uploadDoc[Id], StrCast(uploadDoc.proto!.title)); if (uploadDoc) { DocServer.Mobile.dispatchMobileDocumentUpload({ - docId: uploadDoc[Id] + docId: uploadDoc[Id], + asCollection: asCollection }); } } @@ -230,7 +231,8 @@ export default class MobileInterface extends React.Component {
- + +
Date: Tue, 11 Feb 2020 06:22:04 -0500 Subject: refined upload interaction --- src/client/util/DragManager.ts | 21 ++-- src/client/views/nodes/WebBox.scss | 15 +++ src/client/views/nodes/WebBox.tsx | 130 ++++++++++----------- src/mobile/ImageUpload.tsx | 2 - src/mobile/MobileInkOverlay.scss | 4 +- src/mobile/MobileInkOverlay.tsx | 35 +++--- src/mobile/MobileInterface.scss | 7 +- src/mobile/MobileInterface.tsx | 42 ++++--- src/server/Message.ts | 2 +- .../authentication/models/current_user_utils.ts | 25 ++-- 10 files changed, 146 insertions(+), 137 deletions(-) (limited to 'src/server') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 745540ff9..702c10910 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -195,7 +195,7 @@ export namespace DragManager { dragData.userDropAction === "alias" || (!dragData.userDropAction && dragData.dropAction === "alias") ? Doc.MakeAlias(d) : dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeCopy(d, true) : d) ); - e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) => + e.docDragData ?.droppedDocuments.forEach((drop: Doc, i: number) => Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []).map(prop => drop[prop] = undefined)); }; dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded @@ -288,6 +288,7 @@ export namespace DragManager { if (!ele.parentNode) dragDiv.appendChild(ele); const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement; const rect = ele.getBoundingClientRect(); + console.log("boudning", rect); const scaleX = rect.width / ele.offsetWidth, scaleY = rect.height / ele.offsetHeight; xs.push(rect.left); @@ -305,7 +306,7 @@ export namespace DragManager { dragElement.style.transformOrigin = "0 0"; dragElement.style.borderRadius = getComputedStyle(ele).borderRadius; dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; - dragElement.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`; + dragElement.style.transform = `translate(${rect.left + (options ?.offsetX || 0)}px, ${rect.top + (options ?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`; dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; @@ -334,8 +335,8 @@ export namespace DragManager { return dragElement; }); - const hideSource = options?.hideSource ? true : false; - eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = hideSource) : (ele.hidden = hideSource)); + const hideSource = options ?.hideSource ? true : false; + eles.map(ele => ele.parentElement && ele.parentElement ?.className === dragData.dragDivName ? (ele.parentElement.hidden = hideSource) : (ele.hidden = hideSource)); let lastX = downX; let lastY = downY; @@ -346,7 +347,7 @@ export namespace DragManager { } if (e.shiftKey && CollectionDockingView.Instance) { AbortDrag(); - finishDrag?.(new DragCompleteEvent(true, dragData)); + finishDrag ?.(new DragCompleteEvent(true, dragData)); CollectionDockingView.Instance.StartOtherDrag({ pageX: e.pageX, pageY: e.pageY, @@ -360,13 +361,13 @@ export namespace DragManager { lastX = e.pageX; lastY = e.pageY; dragElements.map((dragElement, i) => (dragElement.style.transform = - `translate(${(xs[i] += moveX) + (options?.offsetX || 0)}px, ${(ys[i] += moveY) + (options?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) + `translate(${(xs[i] += moveX) + (options ?.offsetX || 0)}px, ${(ys[i] += moveY) + (options ?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`) ); }; const hideDragShowOriginalElements = () => { dragElements.map(dragElement => dragElement.parentNode === dragDiv && dragDiv.removeChild(dragElement)); - eles.map(ele => ele.parentElement && ele.parentElement?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false)); + eles.map(ele => ele.parentElement && ele.parentElement ?.className === dragData.dragDivName ? (ele.parentElement.hidden = false) : (ele.hidden = false)); }; const endDrag = () => { document.removeEventListener("pointermove", moveHandler, true); @@ -376,14 +377,14 @@ export namespace DragManager { AbortDrag = () => { hideDragShowOriginalElements(); SelectionManager.SetIsDragging(false); - options?.dragComplete?.(new DragCompleteEvent(true, dragData)); + options ?.dragComplete ?.(new DragCompleteEvent(true, dragData)); endDrag(); }; const upHandler = (e: PointerEvent) => { hideDragShowOriginalElements(); dispatchDrag(eles, e, dragData, options, finishDrag); SelectionManager.SetIsDragging(false); - options?.dragComplete?.(new DragCompleteEvent(false, dragData)); + options ?.dragComplete ?.(new DragCompleteEvent(false, dragData)); endDrag(); }; document.addEventListener("pointermove", moveHandler, true); @@ -404,7 +405,7 @@ export namespace DragManager { }); if (target) { const complete = new DragCompleteEvent(false, dragData); - finishDrag?.(complete); + finishDrag ?.(complete); target.dispatchEvent( new CustomEvent("dashOnDrop", { diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index fbe9bf063..226103a53 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -90,4 +90,19 @@ width: 100%; margin-right: 10px; height: 100%; +} + +.touch-iframe-overlay { + width: 100%; + height: 100%; + position: absolute; + pointer-events: all; + + .indicator { + position: absolute; + + &.active { + background-color: rgba(0, 0, 0, 0.1); + } + } } \ No newline at end of file diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c405dd9d4..ee5bf6f2f 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -39,6 +39,7 @@ export class WebBox extends DocAnnotatableComponent private _longPressSecondsHack?: NodeJS.Timeout; private _iframeRef = React.createRef(); + private _iframeIndicatorRef = React.createRef(); private _iframeDragRef = React.createRef(); @observable private _pressX: number = 0; @observable private _pressY: number = 0; @@ -63,39 +64,6 @@ export class WebBox extends DocAnnotatableComponent componentDidMount() { document.addEventListener("pointerup", this.onLongPressUp); document.addEventListener("pointermove", this.onLongPressMove); - // this._iframeRef.current?.contentWindow?.document.addEventListener("mousedown", (event: MouseEvent) => { - // console.log("clicked inside the iframe?"); - // }); - // const iframe = document.getElementById(this.props.Document.proto![Id]); - // if (iframe) { - // iframe.addEventListener('pointerdown', function (event) { - // const B = iframe.getBoundingClientRect(); - // const e = new CustomEvent('pointerdown', { bubbles: true, cancelable: false }); - // // e.clientX = e.clientX + B?.left; - // // e.clientY = e.clientY + B?.top; - // console.log("custom event pointer down"); - // iframe.dispatchEvent(e); - // }) - // } - // if (this._iframeRef.current) { - // console.log("resetting iframes events"); - // const self = this; - // this._iframeRef.current.addEventListener('pointermove', function (event) { - // const B = self._iframeRef.current?.getBoundingClientRect(); - // const e = new CustomEvent('pointermove', { bubbles: true, cancelable: false }); - // // e.clientX = e.clientX + B?.left; - // // e.clientY = e.clientY + B?.top; - // self._iframeRef.current?.dispatchEvent(e); - // }); - // this._iframeRef.current.addEventListener('pointerdown', function (event) { - // const B = self._iframeRef.current?.getBoundingClientRect(); - // const e = new CustomEvent('pointerdown', { bubbles: true, cancelable: false }); - // // e.clientX = e.clientX + B?.left; - // // e.clientY = e.clientY + B?.top; - // console.log("custom event pointer down"); - // self._iframeRef.current?.dispatchEvent(e); - // }) - // } } componentWillUnmount() { @@ -217,59 +185,75 @@ export class WebBox extends DocAnnotatableComponent } } - // TODO: make this actually a long press onLongPressDown = (e: React.PointerEvent) => { - - console.log("press down", e.clientX, e.clientX); this._pressX = e.clientX; this._pressY = e.clientY; - this._longPressSecondsHack = setTimeout(() => { - console.log("start the drag!!"); - const B = this._iframeRef.current?.getBoundingClientRect(); - const iframeDoc = this._iframeRef.current?.contentDocument; + + // find the pressed element in the iframe (currently only works if its an img) + let pressedElement: HTMLElement | undefined; + let pressedBound: ClientRect | undefined; + if (this._iframeRef.current) { + const B = this._iframeRef.current.getBoundingClientRect(); + const iframeDoc = this._iframeRef.current.contentDocument; if (B && iframeDoc) { - console.log("frame doc", iframeDoc); - console.log("get point", this._pressX, B.left, this._pressY, B.top); + // TODO: this only works when scale = 1 const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top); - console.log("found element", element); - if (element) { - e.stopPropagation(); - e.preventDefault(); - const clone = element.cloneNode(true) as HTMLElement; - - if (clone.nodeName === "IMG") { - const src = clone.getAttribute("src"); // TODO: may not always work - - if (src) { - const doc = Docs.Create.ImageDocument(src, { width: 300 }); - ImageUtils.ExtractExif(doc); - - console.log("start image drag", this._pressX, this._pressY, doc); - // document.dispatchEvent() - const dragData = new DragManager.DocumentDragData([doc]); - DragManager.StartDocumentDrag([clone], dragData, this._pressX, this._pressY); - } + if (element && element.nodeName === "IMG") { + pressedBound = element.getBoundingClientRect(); + pressedElement = element.cloneNode(true) as HTMLElement; + } + } + } + + // mark the pressed element + if (pressedElement && pressedBound) { + console.log("clones b", pressedElement.getBoundingClientRect(), pressedBound); + if (this._iframeIndicatorRef.current) { + this._iframeIndicatorRef.current.style.top = pressedBound.top + "px"; + this._iframeIndicatorRef.current.style.left = pressedBound.left + "px"; + this._iframeIndicatorRef.current.style.width = pressedBound.width + "px"; + this._iframeIndicatorRef.current.style.height = pressedBound.height + "px"; + this._iframeIndicatorRef.current.classList.add("active"); + } + } + + // start dragging the pressed element if long pressed + this._longPressSecondsHack = setTimeout(() => { + if (pressedElement && pressedBound) { + e.stopPropagation(); + e.preventDefault(); + if (pressedElement.nodeName === "IMG") { + const src = pressedElement.getAttribute("src"); // TODO: may not always work + if (src) { + const doc = Docs.Create.ImageDocument(src, { width: 300 }); + ImageUtils.ExtractExif(doc); + + // add clone to div so that dragging ghost is placed properly + if (this._iframeDragRef.current) this._iframeDragRef.current.appendChild(pressedElement); + + const dragData = new DragManager.DocumentDragData([doc]); + DragManager.StartDocumentDrag([pressedElement], dragData, this._pressX, this._pressY, { hideSource: true }); } } } }, 1500); - // e.stopPropagation(); - // e.preventDefault(); } onLongPressMove = (e: PointerEvent) => { - this._pressX = e.clientX; - this._pressY = e.clientY; + // this._pressX = e.clientX; + // this._pressY = e.clientY; } onLongPressUp = (e: PointerEvent) => { - console.log("press up"); if (this._longPressSecondsHack) { clearTimeout(this._longPressSecondsHack); - console.log("long press cancelled"); } - // e.stopPropagation(); - // e.preventDefault(); + if (this._iframeIndicatorRef.current) { + this._iframeIndicatorRef.current.classList.remove("active"); + } + if (this._iframeDragRef.current) { + while (this._iframeDragRef.current.firstChild) this._iframeDragRef.current.removeChild(this._iframeDragRef.current.firstChild); + } } @@ -300,9 +284,13 @@ export class WebBox extends DocAnnotatableComponent
{content}
-
- {!frozen ? (null) :
} - {/* onPointerDown={(e) => { this.onPrePointer(e); this.onLongPressDown(e) }} onPointerMove={this.onPrePointer} onPointerUp={(e) => { this.onPrePointer(e); }} />} */} + {!frozen ? (null) : +
+
+
+
+
+
} ); } render() { diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 10bd78075..42dfd4e51 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -106,8 +106,6 @@ class Uploader extends React.Component { } -// Scripting.addGlobal(function uploadImageMobile() { return Uploader.onClick(); }); - // DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload"); (async () => { diff --git a/src/mobile/MobileInkOverlay.scss b/src/mobile/MobileInkOverlay.scss index 2e45d0441..0b4484519 100644 --- a/src/mobile/MobileInkOverlay.scss +++ b/src/mobile/MobileInkOverlay.scss @@ -1,10 +1,10 @@ .mobileInkOverlay { border: 5px dashed red; + background-color: rgba(0, 0, 0, .05); } .mobileInkOverlay-border { - background-color: rgba(0, 255, 0, .4); - position: absolute; + // background-color: rgba(0, 255, 0, .4); position: absolute; pointer-events: auto; cursor: pointer; diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 9f810424a..db6cf21b4 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -20,6 +20,7 @@ export default class MobileInkOverlay extends React.Component { @observable private _height: number = 0; @observable private _x: number = -300; @observable private _y: number = -300; + @observable private _text: string = ""; @observable private _offsetX: number = 0; @observable private _offsetY: number = 0; @@ -32,21 +33,25 @@ export default class MobileInkOverlay extends React.Component { } initialSize(mobileWidth: number, mobileHeight: number) { - const maxWidth = window.innerWidth - 30; // TODO: may not be window ?? figure out how to not include library ???? + const maxWidth = window.innerWidth - 30; const maxHeight = window.innerHeight - 30; // -30 for padding - const scale = Math.min(maxWidth / mobileWidth, maxHeight / mobileHeight); - return { width: mobileWidth * scale, height: mobileHeight * scale, scale: scale }; + if (mobileWidth > maxWidth || mobileHeight > maxHeight) { + const scale = Math.min(maxWidth / mobileWidth, maxHeight / mobileHeight); + return { width: mobileWidth * scale, height: mobileHeight * scale, scale: scale }; + } + return { width: mobileWidth, height: mobileHeight, scale: 1 }; } @action initMobileInkOverlay(content: MobileInkOverlayContent) { - const { width, height } = content; + const { width, height, text } = content; const scaledSize = this.initialSize(width ? width : 0, height ? height : 0); this._width = scaledSize.width; this._height = scaledSize.height; - this._scale = scaledSize.scale; //scaledSize.scale; + this._scale = scaledSize.scale; this._x = 300; // TODO: center on screen this._y = 25; // TODO: center on screen + this._text = text ? text : ""; } @action @@ -73,7 +78,7 @@ export default class MobileInkOverlay extends React.Component { }; const target = document.elementFromPoint(this._x + 10, this._y + 10); - target?.dispatchEvent( + target ?.dispatchEvent( new CustomEvent("dashOnGesture", { bubbles: true, @@ -88,25 +93,13 @@ export default class MobileInkOverlay extends React.Component { } uploadDocument = async (content: MobileDocumentUploadContent) => { - const { docId, asCollection } = content; - console.log("receive upload document id", docId); + const { docId } = content; const doc = await DocServer.GetRefField(docId); if (doc && doc instanceof Doc) { - console.log("parsed upload document into doc", StrCast(doc.proto!.title)); - const target = document.elementFromPoint(this._x + 10, this._y + 10); - console.log("the target is", target); - - let uploadDocs = [doc]; - if (!asCollection) { - const children = await DocListCastAsync(doc.data); - console.log("uploading children", children); - uploadDocs = children ? children : []; - } - const dragData = new DragManager.DocumentDragData(uploadDocs); + const dragData = new DragManager.DocumentDragData([doc]); const complete = new DragManager.DragCompleteEvent(false, dragData); - console.log("the drag data is", dragData); if (target) { target.dispatchEvent( @@ -181,11 +174,11 @@ export default class MobileInkOverlay extends React.Component { zIndex: 30000, pointerEvents: "none", borderStyle: this._isDragging ? "solid" : "dashed", - backgroundColor: "rgba(255, 0, 0, 0.3)" } } ref={this._mainCont} > +

{this._text}

diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss index 8b0ebcd53..8083e5760 100644 --- a/src/mobile/MobileInterface.scss +++ b/src/mobile/MobileInterface.scss @@ -1,15 +1,18 @@ .mobileInterface-inkInterfaceButtons { position: absolute; - top: -50px; + top: 0px; display: flex; justify-content: space-between; width: 100%; z-index: 9999; height: 50px; + + .mobileInterface-button { + height: 100%; + } } .mobileInterface-container { height: calc(100% - 50px); - margin-top: 50px; position: relative; } \ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index e21258c62..a3b956a15 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -34,6 +34,7 @@ import MarqueeOptionsMenu from '../client/views/collections/collectionFreeForm/M import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationManager'; import { listSpec } from '../new_fields/Schema'; import { Id } from '../new_fields/FieldSymbols'; +import { DocumentManager } from '../client/util/DocumentManager'; library.add(faLongArrowAltLeft); @@ -73,7 +74,6 @@ export default class MobileInterface extends React.Component { onSwitch && onSwitch(); this.renderView = renderView; - console.log("switching current view", renderView); } onSwitchInking = () => { @@ -87,22 +87,37 @@ export default class MobileInterface extends React.Component { }); } - onSwitchUpload = () => { + onSwitchUpload = async () => { + let width = 300; + let height = 300; + + // 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: 100, - height: 100 + width: width, + height: height, + text: "Documents uploaded from mobile will show here", }); } renderDefaultContent = () => { - console.log("rendering default content", this.mainContainer); if (this.mainContainer) { return { console.log("want to add doc to default content", StrCast(doc.title)); return false; }} + addDocument={returnFalse} addDocTab={returnFalse} pinToPres={emptyFunction} removeDocument={undefined} @@ -142,7 +157,6 @@ export default class MobileInterface extends React.Component { } shiftLeft = (e: React.MouseEvent) => { - console.log("shift left!"); DocServer.Mobile.dispatchOverlayPositionUpdate({ dx: -10 }); @@ -203,17 +217,16 @@ export default class MobileInterface extends React.Component { } } - upload = async (e: React.MouseEvent, asCollection: boolean) => { + upload = async (e: React.MouseEvent) => { if (this.mainContainer) { const data = Cast(this.mainContainer.data, listSpec(Doc)); if (data) { - const uploadDoc = await data[1]; // TODO: ensure this is the collection to upload - - console.log("UPLOADING DOCUMENT FROM MOBILE", uploadDoc[Id], StrCast(uploadDoc.proto!.title)); + const collectionDoc = await data[1]; // this should be the collection doc since the positions should be locked + const children = Cast(collectionDoc.data, listSpec(Doc), []); + const uploadDoc = children.length === 1 ? await children[0] : collectionDoc; if (uploadDoc) { DocServer.Mobile.dispatchMobileDocumentUpload({ docId: uploadDoc[Id], - asCollection: asCollection }); } } @@ -231,15 +244,14 @@ export default class MobileInterface extends React.Component {
- - +
{ console.log("want to add doc", StrCast(doc.title)); return false; }} + addDocument={returnFalse} addDocTab={returnFalse} pinToPres={emptyFunction} removeDocument={undefined} diff --git a/src/server/Message.ts b/src/server/Message.ts index 6dac37a46..b7bf2e81e 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -55,6 +55,7 @@ export interface MobileInkOverlayContent { readonly enableOverlay: boolean; readonly width?: number; readonly height?: number; + readonly text?: string; } export interface UpdateMobileInkOverlayPositionContent { @@ -65,7 +66,6 @@ export interface UpdateMobileInkOverlayPositionContent { export interface MobileDocumentUploadContent { readonly docId: string; - readonly asCollection: boolean; } export namespace MessageStore { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 3e5953ac1..491685e18 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -102,9 +102,9 @@ export class CurrentUserUtils { { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "pink", activePen: doc }, { title: "use scrubber", icon: "eraser", click: 'activateScrubber(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "green", activePen: doc }, { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, - { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, + // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "red", activePen: doc }, { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" }, - { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, + // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, ]; 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, @@ -138,9 +138,7 @@ export class CurrentUserUtils { } static setupMobileDoc(userDoc: Doc) { - const webDoc = Docs.Create.WebDocument("https://wikipedia.com", { title: "Mobile Upload Web", chromeStatus: "enabled" }); - - return userDoc.activeMoble ?? Docs.Create.MasonryDocument([webDoc, ...CurrentUserUtils.setupMobileButtons(userDoc)], { + return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), { columnWidth: 100, ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "buttons", autoHeight: true, yMargin: 5 }); } @@ -150,14 +148,15 @@ export class CurrentUserUtils { } static setupMobileUploadDoc(userDoc: Doc) { - const webDoc = Docs.Create.WebDocument("https://yahoo.com", { title: "Upload Images From the Web", chromeStatus: "enabled" }); - const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload Collection", backgroundColor: "pink" }); - console.log("window size", window.innerWidth, window.innerHeight); - // return Docs.Create.StackingDocument([webDoc, uploadDoc], { - // columnWidth: window.innerWidth, //ignoreClick: true, lockedPosition: true, chromeStatus: "disabled", title: "Mobile Upload", autoHeight: true, yMargin: 5 - // }); - return Docs.Create.StackingDocument([webDoc, uploadDoc], {//...CurrentUserUtils.setupMobileButtons(userDoc)], { - columnWidth: 100, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 30 + const webDoc = Docs.Create.WebDocument("https://www.britannica.com/animal/cat", { + title: "Upload Images From the Web", chromeStatus: "enabled", lockedPosition: true + }); + const uploadDoc = Docs.Create.StackingDocument([], { + title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true + }); + console.log(window.innerWidth, screen.width, window.devicePixelRatio); + return Docs.Create.StackingDocument([webDoc, uploadDoc], { + columnWidth: screen.width - 10, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 80, backgroundColor: "lightgray" }); } -- cgit v1.2.3-70-g09d2 From 47b939e9799da2f57047a15113c116d8ba31ce5e Mon Sep 17 00:00:00 2001 From: vellichora Date: Tue, 11 Feb 2020 10:49:25 -0500 Subject: fixed some small errors --- package-lock.json | 56 ++++++++-------------- package.json | 4 +- src/client/views/nodes/WebBox.tsx | 2 +- src/mobile/MobileInkOverlay.tsx | 5 +- src/mobile/MobileInterface.tsx | 2 - .../authentication/models/current_user_utils.ts | 4 +- 6 files changed, 28 insertions(+), 45 deletions(-) (limited to 'src/server') diff --git a/package-lock.json b/package-lock.json index 833710fe7..5492f7dbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5682,8 +5682,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -5701,13 +5700,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5720,18 +5717,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -5834,8 +5828,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -5845,7 +5838,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5858,20 +5850,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5888,7 +5877,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5969,8 +5957,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -5980,7 +5967,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6056,8 +6042,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -6087,7 +6072,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6105,7 +6089,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6144,13 +6127,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -14665,19 +14646,22 @@ "dev": true }, "resilient-server-session": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/resilient-server-session/-/resilient-server-session-1.1.2.tgz", - "integrity": "sha512-eLoXxTc5bFOYH2JejSCYc2O8emoo80p2zOuwVVWVoK6/2NJBzLP8Yl7kU8m7tJDrOoqDSZGghsVD5ob9BbUgAQ==", + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/resilient-server-session/-/resilient-server-session-1.1.9.tgz", + "integrity": "sha512-XSVujTyJOQMACllXUvWOSHY4GK4JI6aECjCrQR0UBvd2+hdjM1euffspn2b+7M0fepo+bJ71YrAOA9M34ChBZw==", "requires": { "@types/chai": "^4.2.7", + "@types/express": "^4.17.2", "@types/mocha": "^5.2.7", "@types/node": "^10.12.30", "@types/request-promise": "^4.1.42", "@types/uuid": "^3.4.6", "chai": "^4.2.0", "colors": "^1.4.0", + "express": "^4.17.1", "jsonschema": "^1.2.5", "mocha": "^7.0.0", + "request": "^2.88.0", "request-promise": "^4.2.5", "typescript": "^3.7.4", "uuid": "^3.3.3" @@ -14842,9 +14826,9 @@ } }, "mocha": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.0.tgz", - "integrity": "sha512-CirsOPbO3jU86YKjjMzFLcXIb5YiGLUrjrXFHoJ3e2z9vWiaZVCZQ2+gtRGMPWF+nFhN6AWwLM/juzAQ6KRkbA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.0.1.tgz", + "integrity": "sha512-9eWmWTdHLXh72rGrdZjNbG3aa1/3NRPpul1z0D979QpEnFdCG0Q5tv834N+94QEN2cysfV72YocQ3fn87s70fg==", "requires": { "ansi-colors": "3.2.3", "browser-stdout": "1.3.1", diff --git a/package.json b/package.json index 67b9b1630..6a2b5fac4 100644 --- a/package.json +++ b/package.json @@ -233,7 +233,7 @@ "readline": "^1.3.0", "request": "^2.88.0", "request-promise": "^4.2.5", - "resilient-server-session": "^1.1.2", + "resilient-server-session": "^1.1.9", "rimraf": "^3.0.0", "serializr": "^1.5.4", "sharp": "^0.23.4", @@ -253,4 +253,4 @@ "xoauth2": "^1.2.0", "youtube": "^0.1.0" } -} \ No newline at end of file +} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 082a9a965..d486253b8 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -222,7 +222,7 @@ export class WebBox extends DocAnnotatableComponent if (pressedElement.nodeName === "IMG") { const src = pressedElement.getAttribute("src"); // TODO: may not always work if (src) { - const doc = Docs.Create.ImageDocument(src, { width: 300 }); + const doc = Docs.Create.ImageDocument(src, { _width: 300 }); ImageUtils.ExtractExif(doc); // add clone to div so that dragging ghost is placed properly diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index db6cf21b4..4dde3a075 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -78,7 +78,7 @@ export default class MobileInkOverlay extends React.Component { }; const target = document.elementFromPoint(this._x + 10, this._y + 10); - target ?.dispatchEvent( + target?.dispatchEvent( new CustomEvent("dashOnGesture", { bubbles: true, @@ -112,7 +112,8 @@ export default class MobileInkOverlay extends React.Component { complete: complete, altKey: false, metaKey: false, - ctrlKey: false + ctrlKey: false, + shiftKey: false } } ) diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index d0954a84b..07ee611ee 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -206,7 +206,6 @@ export default class MobileInterface extends React.Component { ContentScaling={returnOne} whenActiveChanged={returnFalse} ScreenToLocalTransform={Transform.Identity} - ruleProvider={undefined} renderDepth={0} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined}> @@ -254,7 +253,6 @@ export default class MobileInterface extends React.Component { addDocTab={returnFalse} pinToPres={emptyFunction} removeDocument={undefined} - ruleProvider={undefined} onClick={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 4a765e8d3..aa9f3649e 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -156,14 +156,14 @@ export class CurrentUserUtils { static setupMobileUploadDoc(userDoc: Doc) { const webDoc = Docs.Create.WebDocument("https://www.britannica.com/animal/cat", { - title: "Upload Images From the Web", chromeStatus: "enabled", lockedPosition: true + title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true }); const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true }); console.log(window.innerWidth, screen.width, window.devicePixelRatio); return Docs.Create.StackingDocument([webDoc, uploadDoc], { - columnWidth: screen.width - 10, lockedPosition: true, chromeStatus: "disabled", title: "Upload", autoHeight: true, yMargin: 80, backgroundColor: "lightgray" + columnWidth: screen.width - 10, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray" }); } -- cgit v1.2.3-70-g09d2 From 864cba561db8e26240b093da7ab524e76c8823d1 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Tue, 11 Feb 2020 22:47:23 -0500 Subject: small fixes for mobile remote upload --- package-lock.json | 41 ++++++++++++++++------ src/client/views/nodes/WebBox.tsx | 12 +++++-- src/mobile/MobileInkOverlay.scss | 5 +-- src/mobile/MobileInterface.scss | 2 +- src/mobile/MobileInterface.tsx | 8 +++-- src/server/DashSession/DashSessionAgent.ts | 21 ++++++----- .../authentication/models/current_user_utils.ts | 3 +- src/server/index.ts | 2 +- 8 files changed, 63 insertions(+), 31 deletions(-) (limited to 'src/server') diff --git a/package-lock.json b/package-lock.json index 5492f7dbf..1741b50dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5682,7 +5682,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -5700,11 +5701,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" @@ -5717,15 +5720,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", @@ -5828,7 +5834,8 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -5838,6 +5845,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5850,17 +5858,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "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" @@ -5877,6 +5888,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -5957,7 +5969,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -5967,6 +5980,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -6042,7 +6056,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -6072,6 +6087,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", @@ -6089,6 +6105,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6127,11 +6144,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.1.1", - "bundled": true + "bundled": true, + "optional": true } } }, diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index d486253b8..6cae4e878 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -193,9 +193,17 @@ export class WebBox extends DocAnnotatableComponent const B = this._iframeRef.current.getBoundingClientRect(); const iframeDoc = this._iframeRef.current.contentDocument; if (B && iframeDoc) { - // TODO: this only works when scale = 1 + // check if there is selected text + const selectedText = iframeDoc.getSelection(); + if (selectedText && selectedText.toString.length > -1) { + + } + console.log("selectedText", selectedText ? selectedText.toString() : ""); + + // TODO: this only works when scale = 1 as it is currently only inteded for mobile upload const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top); - if (element && element.nodeName === "IMG") { + console.log("found element", element, element && element.nodeName); + if (element && element.nodeName) {//} === "IMG") { pressedBound = element.getBoundingClientRect(); pressedElement = element.cloneNode(true) as HTMLElement; } diff --git a/src/mobile/MobileInkOverlay.scss b/src/mobile/MobileInkOverlay.scss index 0b4484519..b9c1fb146 100644 --- a/src/mobile/MobileInkOverlay.scss +++ b/src/mobile/MobileInkOverlay.scss @@ -1,10 +1,11 @@ .mobileInkOverlay { - border: 5px dashed red; + border: 10px dashed red; background-color: rgba(0, 0, 0, .05); } .mobileInkOverlay-border { - // background-color: rgba(0, 255, 0, .4); position: absolute; + // background-color: rgba(0, 255, 0, .4); + position: absolute; pointer-events: auto; cursor: pointer; diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss index 8083e5760..d0849dbc7 100644 --- a/src/mobile/MobileInterface.scss +++ b/src/mobile/MobileInterface.scss @@ -13,6 +13,6 @@ } .mobileInterface-container { - height: calc(100% - 50px); + height: 100%; position: relative; } \ No newline at end of file diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 07ee611ee..83410b99d 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -3,7 +3,7 @@ import { observer } from 'mobx-react'; import { computed, action, observable } from 'mobx'; import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; import { FieldValue, Cast, StrCast } from '../new_fields/Types'; -import { Doc } from '../new_fields/Doc'; +import { Doc, DocListCast } from '../new_fields/Doc'; import { Docs } from '../client/documents/Documents'; import { CollectionView } from '../client/views/collections/CollectionView'; import { DocumentView } from '../client/views/nodes/DocumentView'; @@ -220,8 +220,10 @@ export default class MobileInterface extends React.Component { 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 = Cast(collectionDoc.data, listSpec(Doc), []); - const uploadDoc = children.length === 1 ? await children[0] : collectionDoc; + 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], diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts index c55e01243..44f77c049 100644 --- a/src/server/DashSession/DashSessionAgent.ts +++ b/src/server/DashSession/DashSessionAgent.ts @@ -25,15 +25,18 @@ export class DashSessionAgent extends AppliedSessionAgent { * The core method invoked when the single master thread is initialized. * Installs event hooks, repl commands and additional IPC listeners. */ - protected async initializeMonitor(monitor: Monitor, sessionKey: string): Promise { - await this.dispatchSessionPassword(sessionKey); - monitor.addReplCommand("pull", [], () => monitor.exec("git pull")); - monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand); - monitor.addReplCommand("backup", [], this.backup); - monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); - monitor.on("backup", this.backup); - monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to)); - monitor.coreHooks.onCrashDetected(this.dispatchCrashReport); + // protected async initializeMonitor(monitor: Monitor, sessionKey: string): Promise { + protected async initializeMonitor(monitor: Monitor): Promise { + + // await this.dispatchSessionPassword(sessionKey); + // monitor.addReplCommand("pull", [], () => monitor.exec("git pull")); + // monitor.addReplCommand("solr", [/start|stop|index/], this.executeSolrCommand); + // monitor.addReplCommand("backup", [], this.backup); + // monitor.addReplCommand("debug", [/\S+\@\S+/], async ([to]) => this.dispatchZippedDebugBackup(to)); + // monitor.on("backup", this.backup); + // monitor.on("debug", async ({ to }) => this.dispatchZippedDebugBackup(to)); + // monitor.coreHooks.onCrashDetected(this.dispatchCrashReport); + return ""; } /** diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index aa9f3649e..6c916689a 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -161,9 +161,8 @@ export class CurrentUserUtils { const uploadDoc = Docs.Create.StackingDocument([], { title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true }); - console.log(window.innerWidth, screen.width, window.devicePixelRatio); return Docs.Create.StackingDocument([webDoc, uploadDoc], { - columnWidth: screen.width - 10, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray" + _width: screen.width, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray" }); } diff --git a/src/server/index.ts b/src/server/index.ts index 313a2f0e2..55ba71dba 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -141,7 +141,7 @@ export async function launchServer() { * So, the 'else' clause is exactly what we've always run when executing npm start. */ if (process.env.RELEASE) { - (sessionAgent = new DashSessionAgent()).launch(); + // (sessionAgent = new DashSessionAgent()).launch(); } else { launchServer(); } -- cgit v1.2.3-70-g09d2