From e08c0d5b228c8ca1103bb0d7368f3f65bb24b675 Mon Sep 17 00:00:00 2001
From: Fawn <fangrui_tong@brown.edu>
Date: Wed, 15 Jan 2020 17:49:37 -0500
Subject: abstracted mobile ink overlay stuff into its own component

---
 src/mobile/MobileInkOverlay.tsx | 75 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)
 create mode 100644 src/mobile/MobileInkOverlay.tsx

(limited to 'src/mobile/MobileInkOverlay.tsx')

diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx
new file mode 100644
index 000000000..240d23b32
--- /dev/null
+++ b/src/mobile/MobileInkOverlay.tsx
@@ -0,0 +1,75 @@
+import React = require('react');
+import { observer } from "mobx-react";
+import { MobileInkBoxContent, GestureContent } from "../server/Message";
+import { observable, action } from "mobx";
+import { GestureUtils } from "../pen-gestures/GestureUtils";
+
+
+@observer
+export default class MobileInkOverlay extends React.Component {
+    public static Instance: MobileInkOverlay;
+
+    private _mobileWidth: number = 0;
+    private _mobileHeight: number = 0;
+    @observable private _width: number = 0;
+    @observable private _height: number = 0;
+    @observable private _x: number = -300;
+    @observable private _y: number = -300;
+
+    constructor(props: Readonly<{}>) {
+        super(props);
+        MobileInkOverlay.Instance = this;
+    }
+
+    @action
+    initMobileInkOverlay(content: MobileInkBoxContent) {
+        const { width, height } = content;
+        this._mobileWidth = width ? width : 0;
+        this._mobileHeight = height ? height : 0;
+        this._width = width ? width : 0;
+        this._height = height ? height : 0;
+        this._x = 300; // TODO: center on screen
+        this._y = 25; // TODO: center on screen
+    }
+
+    drawStroke = (content: GestureContent) => {
+        const { points, bounds } = content;
+        const scale = 1;
+
+        const B = {
+            right: bounds.right + this._x,
+            left: bounds.left + this._x, // TODO: scale
+            bottom: bounds.bottom + this._y,
+            top: bounds.top + this._y, // TODO: scale
+            width: bounds.width * scale,
+            height: bounds.height * scale,
+        };
+
+        const target = document.elementFromPoint(points[0].X, points[0].Y);
+        target?.dispatchEvent(
+            new CustomEvent<GestureUtils.GestureEvent>("dashOnGesture",
+                {
+                    bubbles: true,
+                    detail: {
+                        points: points,
+                        gesture: GestureUtils.Gestures.Stroke,
+                        bounds: B
+                    }
+                }
+            )
+        );
+    }
+
+    render() {
+        return (
+            <div className="mobileInkOverlay" style={{
+                width: this._width,
+                height: this._height,
+                position: "absolute",
+                transform: `translate(${this._x}px, ${this._y}px)`,
+                zIndex: 30000,
+                pointerEvents: "none"
+            }}></div>
+        );
+    }
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From d2530f906d68e47cc25359cd8d85684a0e29637a Mon Sep 17 00:00:00 2001
From: Fawn <fangrui_tong@brown.edu>
Date: Wed, 15 Jan 2020 18:06:05 -0500
Subject: strokes drawn on mobile interface are translated properly to desktop
 mobile ink overlay

---
 src/mobile/MobileInkOverlay.tsx | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

(limited to 'src/mobile/MobileInkOverlay.tsx')

diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx
index 240d23b32..71dd20c51 100644
--- a/src/mobile/MobileInkOverlay.tsx
+++ b/src/mobile/MobileInkOverlay.tsx
@@ -9,8 +9,7 @@ import { GestureUtils } from "../pen-gestures/GestureUtils";
 export default class MobileInkOverlay extends React.Component {
     public static Instance: MobileInkOverlay;
 
-    private _mobileWidth: number = 0;
-    private _mobileHeight: number = 0;
+    @observable private _scale: number = 1;
     @observable private _width: number = 0;
     @observable private _height: number = 0;
     @observable private _x: number = -300;
@@ -21,28 +20,34 @@ export default class MobileInkOverlay extends React.Component {
         MobileInkOverlay.Instance = this;
     }
 
+    initialSize(mobileWidth: number, mobileHeight: number) {
+        const maxWidth = window.innerWidth - 30; // TODO: may not be window ?? figure out how to not include library ????
+        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 };
+    }
+
     @action
     initMobileInkOverlay(content: MobileInkBoxContent) {
         const { width, height } = content;
-        this._mobileWidth = width ? width : 0;
-        this._mobileHeight = height ? height : 0;
-        this._width = width ? width : 0;
-        this._height = height ? height : 0;
+        const scaledSize = this.initialSize(width ? width : 0, height ? height : 0);
+        this._width = scaledSize.width;
+        this._height = scaledSize.height;
+        this._scale = scaledSize.scale;
         this._x = 300; // TODO: center on screen
         this._y = 25; // TODO: center on screen
     }
 
     drawStroke = (content: GestureContent) => {
         const { points, bounds } = content;
-        const scale = 1;
 
         const B = {
-            right: bounds.right + this._x,
-            left: bounds.left + this._x, // TODO: scale
-            bottom: bounds.bottom + this._y,
-            top: bounds.top + this._y, // TODO: scale
-            width: bounds.width * scale,
-            height: bounds.height * scale,
+            right: (bounds.right * this._scale) + this._x,
+            left: (bounds.left * this._scale) + this._x, // TODO: scale
+            bottom: (bounds.bottom * this._scale) + this._y,
+            top: (bounds.top * this._scale) + this._y, // TODO: scale
+            width: bounds.width * this._scale,
+            height: bounds.height * this._scale,
         };
 
         const target = document.elementFromPoint(points[0].X, points[0].Y);
-- 
cgit v1.2.3-70-g09d2


From ecf0f5b8f426db9e66c05e759f61294811b15fca Mon Sep 17 00:00:00 2001
From: vellichora <fangrui_tong@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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<number, React.Touch>, ignorePen: boolean): React.Touch[] {
-        const myTouches = new Array<React.Touch>();
-        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<number, React.Touch>, 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<TouchInteraction>, 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<number, React.Touch>, ignorePen: boolean): React.Touch[] {
+        const myTouches = new Array<React.Touch>();
+        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 (
+            <polyline
+                points={pts}
+                style={{
+                    fill: "none",
+                    stroke: color,
+                    strokeWidth: width
+                }}
+            />
+        );
+    }
+
+    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<number, React.Touch>, 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<TouchInteraction>, 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 (
-            <polyline
-                points={pts}
-                style={{
-                    fill: "none",
-                    stroke: color ?? InkingControl.Instance.selectedColor,
-                    strokeWidth: width ?? InkingControl.Instance.selectedWidth
-                }}
-            />
-        );
-    }
-
     @computed get currentStroke() {
         if (this._points.length <= 1) {
             return (null);
@@ -241,23 +226,23 @@ export default class GestureOverlay extends Touchable {
 
         return (
             <svg width={B.width} height={B.height} style={{ transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000 }}>
-                {this.CreatePolyline(this._points, B.left, B.top, this.Color, this.Width)}
+                {InteractionUtils.CreatePolyline(this._points, B.left, B.top, this.Color, this.Width)}
             </svg>
         );
     }
 
     @action
-    enableMobileInkBox = (content: MobileInkBoxContent) => {
-        this.showMobileInkOverlay = content.enableBox;
+    enableMobileInkOverlay = (content: MobileInkOverlayContent) => {
+        this.showMobileInkOverlay = content.enableOverlay;
     }
 
     render() {
         return (
             <div className="gestureOverlay-cont" onPointerDown={this.onPointerDown} onTouchStart={this.onTouchStart}>
+                {this.showMobileInkOverlay ? <MobileInkOverlay /> : <></>}
                 {this.currentStroke}
                 {this.props.children}
                 {this._palette}
-                {this.showMobileInkOverlay ? <MobileInkOverlay /> : <></>}
             </div>);
     }
 }
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 (
-        <polyline
-            points={pts}
-            style={{
-                fill: "none",
-                stroke: color ?? InkingControl.Instance.selectedColor,
-                strokeWidth: width ?? InkingControl.Instance.selectedWidth
-            }}
-        />
-    );
-}
-
 @observer
 export class InkingStroke extends DocExtendableComponent<FieldViewProps, InkDocument>(InkDocument) {
     public static LayoutString(fieldStr: string) { return FieldView.LayoutString(InkingStroke, fieldStr); }
@@ -44,7 +31,7 @@ export class InkingStroke extends DocExtendableComponent<FieldViewProps, InkDocu
         const top = Math.min(...ys);
         const right = Math.max(...xs);
         const bottom = Math.max(...ys);
-        const points = CreatePolyline(data, left, top, this.Document.color, this.Document.strokeWidth);
+        const points = InteractionUtils.CreatePolyline(data, left, top, this.Document.color ?? InkingControl.Instance.selectedColor, this.Document.strokeWidth ?? parseInt(InkingControl.Instance.selectedWidth));
         const width = right - left;
         const height = bottom - top;
         const scaleX = this.PanelWidth / width;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index bbfd22f50..4d216cb2a 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -26,7 +26,6 @@ import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"
 import { ContextMenu } from "../../ContextMenu";
 import { ContextMenuProps } from "../../ContextMenuItem";
 import { InkingControl } from "../../InkingControl";
-import { CreatePolyline } from "../../InkingStroke";
 import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
 import { DocumentViewProps } from "../../nodes/DocumentView";
 import { FormattedTextBox } from "../../nodes/FormattedTextBox";
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 2e0ae09ba..03f37595f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -443,6 +443,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(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<HTMLDivElement> = 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 (
-            <div className="mobileInkOverlay" style={{
-                width: this._width,
-                height: this._height,
-                position: "absolute",
-                transform: `translate(${this._x}px, ${this._y}px)`,
-                zIndex: 30000,
-                pointerEvents: "none"
-            }}></div>
+            <div className="mobileInkOverlay"
+                style={{
+                    width: this._width,
+                    height: this._height,
+                    position: "absolute",
+                    transform: `translate(${this._x}px, ${this._y}px)`,
+                    zIndex: 30000,
+                    pointerEvents: "none",
+                    borderStyle: this._isDragging ? "solid" : "dashed"
+                }}
+                ref={this._mainCont}
+            >
+                <div className="mobileInkOverlay-border top" onPointerDown={this.dragStart}></div>
+                <div className="mobileInkOverlay-border bottom" onPointerDown={this.dragStart}></div>
+                <div className="mobileInkOverlay-border left" onPointerDown={this.dragStart}></div>
+                <div className="mobileInkOverlay-border right" onPointerDown={this.dragStart}></div>
+            </div>
         );
     }
 }
\ 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 (
-                <GestureOverlay>
-                    <div className="mobileInterface-topButtons">
-                        <button className="mobileInterface-button cancel" onClick={this.onClick} title="Cancel drawing"><FontAwesomeIcon icon="trash" /></button>
-                        <button className="mobileInterface-button cancel" onClick={this.onClick} title="Insert drawing"><FontAwesomeIcon icon="check" /></button>
+                <div className="mobileInterface">
+                    <div className="mobileInterface-inkInterfaceButtons">
+                        <div className="navButtons">
+                            <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button>
+                        </div>
+                        <div className="inkSettingButtons">
+                            <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button>
+                        </div>
+                        <div className="navButtons">
+                            <button className="mobileInterface-button" onClick={this.shiftLeft} title="Shift left">left</button>
+                            <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button>
+                        </div>
                     </div>
-                    <CollectionView
-                        Document={this.mainContainer}
-                        DataDoc={undefined}
-                        LibraryPath={emptyPath}
-                        fieldKey={""}
-                        addDocTab={returnFalse}
-                        pinToPres={emptyFunction}
-                        PanelHeight={() => 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}>
-                    </CollectionView>
-                </GestureOverlay>
+                    <GestureOverlay>
+                        <CollectionView
+                            Document={this.mainContainer}
+                            DataDoc={undefined}
+                            LibraryPath={emptyPath}
+                            fieldKey={""}
+                            addDocTab={returnFalse}
+                            pinToPres={emptyFunction}
+                            PanelHeight={() => 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}>
+                        </CollectionView>
+                    </GestureOverlay>
+                </div>
             );
         }
     }
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<string>("Foo");
     export const Bar = new Message<string>("Bar");
@@ -65,8 +71,10 @@ export namespace MessageStore {
     export const GetDocument = new Message<string>("Get Document");
     export const DeleteAll = new Message<any>("Delete All");
     export const ConnectionTerminated = new Message<string>("Connection Terminated");
+
     export const GesturePoints = new Message<GestureContent>("Gesture Points");
-    export const MobileInkBoxTrigger = new Message<MobileInkBoxContent>("Trigger Mobile Ink Box");
+    export const MobileInkOverlayTrigger = new Message<MobileInkOverlayContent>("Trigger Mobile Ink Overlay");
+    export const UpdateMobileInkOverlayPosition = new Message<UpdateMobileInkOverlayPosition>("Update Mobile Ink Overlay Position");
 
     export const GetRefField = new Message<string>("Get Ref Field");
     export const GetRefFields = new Message<string[]>("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 <fangrui_tong@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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 {
                 <div className="mobileInterface">
                     <div className="mobileInterface-inkInterfaceButtons">
                         <div className="navButtons">
-                            <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button>
+                            <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing">BACK</button>
                         </div>
                         <div className="inkSettingButtons">
                             <button className="mobileInterface-button cancel" onClick={this.onBack} title="Cancel drawing"><FontAwesomeIcon icon="long-arrow-alt-left" /></button>
@@ -185,8 +198,57 @@ export default class MobileInterface extends React.Component {
         }
     }
 
+    upload = () => {
+
+    }
+
+    @computed
+    get uploadContent() {
+        if (this.mainContainer) {
+            return (
+                <div className="mobileInterface">
+                    <div className="mobileInterface-inkInterfaceButtons">
+                        <div className="navButtons">
+                            <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
+                        </div>
+                        <div className="uploadSettings">
+                            <button className="mobileInterface-button" onClick={this.upload} title="Shift left">UPLOAD</button>
+                        </div>
+                    </div>
+                    <DocumentView
+                        Document={this.mainContainer}
+                        DataDoc={undefined}
+                        LibraryPath={emptyPath}
+                        addDocument={returnFalse}
+                        addDocTab={returnFalse}
+                        pinToPres={emptyFunction}
+                        removeDocument={undefined}
+                        ruleProvider={undefined}
+                        onClick={undefined}
+                        ScreenToLocalTransform={Transform.Identity}
+                        ContentScaling={returnOne}
+                        PanelWidth={() => 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}>
+                    </DocumentView>
+                </div>
+            );
+        }
+    }
+
     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 (
             <div className="mobile-container">
                 {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<GestureContent>("Gesture Points");
     export const MobileInkOverlayTrigger = new Message<MobileInkOverlayContent>("Trigger Mobile Ink Overlay");
-    export const UpdateMobileInkOverlayPosition = new Message<UpdateMobileInkOverlayPosition>("Update Mobile Ink Overlay Position");
+    export const UpdateMobileInkOverlayPosition = new Message<UpdateMobileInkOverlayPositionContent>("Update Mobile Ink Overlay Position");
 
     export const GetRefField = new Message<string>("Get Ref Field");
     export const GetRefFields = new Message<string[]>("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 <fangrui_tong@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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<FieldViewProps, WebDocument>
                 {view}
             </div>;
 
-        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 (
             <>
                 <div className={classname}  >
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<HTMLInputElement>();
 
 @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 <DocumentView
                 Document={this.mainContainer}
@@ -121,7 +143,7 @@ export default class MobileInterface extends React.Component {
     }
 
     onBack = (e: React.MouseEvent) => {
-        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 (
                 <div className="mobileInterface">
@@ -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 (
             <div className="mobile-container">
-                {content}
+                {this.renderView ? this.renderView() : this.renderDefaultContent()}
             </div>
         );
     }
 }
 
-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 <fangrui_tong@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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<DropEvent>).detail);
+        const handler = (e: Event) => { console.log("drop target reveied docs"); dropFunc(e, (e as CustomEvent<DropEvent>).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<CMVFieldRowPr
 
     @undoBatch
     rowDrop = action((e: Event, de: DragManager.DropEvent) => {
+        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<void> => {
+        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<CSVFieldC
 
     @undoBatch
     columnDrop = action((e: Event, de: DragManager.DropEvent) => {
+        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<FieldViewProps> {
         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<CollectionViewChro
 
     @action
     toggleCollapse = () => {
+        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<GestureUtils.GestureEvent>("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<DragManager.DropEvent>("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}
             >
                 <div className="mobileInkOverlay-border top" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border bottom" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border left" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border right" onPointerDown={this.dragStart}></div>
-            </div>
+            </div >
         );
     }
 }
\ 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 <DocumentView
                 Document={this.mainContainer}
                 DataDoc={undefined}
                 LibraryPath={emptyPath}
-                addDocument={returnFalse}
+                addDocument={(doc: Doc) => { 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 {
                             <button className="mobileInterface-button" onClick={this.shiftRight} title="Shift right">right</button>
                         </div>
                     </div>
-                    <GestureOverlay>
-                        <CollectionView
-                            Document={this.mainContainer}
-                            DataDoc={undefined}
-                            LibraryPath={emptyPath}
-                            fieldKey={""}
-                            addDocTab={returnFalse}
-                            pinToPres={emptyFunction}
-                            PanelHeight={() => 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}>
-                        </CollectionView>
-                    </GestureOverlay>
+                    <CollectionView
+                        Document={this.mainContainer}
+                        DataDoc={undefined}
+                        LibraryPath={emptyPath}
+                        fieldKey={""}
+                        addDocTab={returnFalse}
+                        pinToPres={emptyFunction}
+                        PanelHeight={() => 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}>
+                    </CollectionView>
                 </div>
             );
         }
     }
 
-    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 (
-                <div className="mobileInterface">
+                <div className="mobileInterface" onDragOver={this.onDragOver}>
                     <div className="mobileInterface-inkInterfaceButtons">
                         <div className="navButtons">
                             <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
@@ -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 (
-            <div className="mobile-container">
-                {this.renderView ? this.renderView() : this.renderDefaultContent()}
+            <div className="mobileInterface-container" onDragOver={this.onDragOver}>
+                {/* <DocumentDecorations />
+                <GestureOverlay>
+                    {this.renderView ? this.renderView() : this.renderDefaultContent()}
+                </GestureOverlay> */}
+
+                {/* <DictationOverlay />
+                <SharingManager />
+                <GoogleAuthenticationManager /> */}
+                <DocumentDecorations />
+                <GestureOverlay>
+                    {this.renderView ? this.renderView() : this.renderDefaultContent()}
+                </GestureOverlay>
+                <PreviewCursor />
+                {/* <ContextMenu /> */}
+                <RadialMenu />
+                {/* <PDFMenu />
+                <MarqueeOptionsMenu />
+                <OverlayView /> */}
             </div>
         );
     }
@@ -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<T> {
     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<string>("Foo");
     export const Bar = new Message<string>("Bar");
@@ -75,6 +80,7 @@ export namespace MessageStore {
     export const GesturePoints = new Message<GestureContent>("Gesture Points");
     export const MobileInkOverlayTrigger = new Message<MobileInkOverlayContent>("Trigger Mobile Ink Overlay");
     export const UpdateMobileInkOverlayPosition = new Message<UpdateMobileInkOverlayPositionContent>("Update Mobile Ink Overlay Position");
+    export const MobileDocumentUpload = new Message<MobileDocumentUploadContent>("Upload Document From Mobile");
 
     export const GetRefField = new Message<string>("Get Ref Field");
     export const GetRefFields = new Message<string[]>("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 <fangrui_tong@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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 {
                             <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
                         </div>
                         <div className="uploadSettings">
-                            <button className="mobileInterface-button" onClick={this.upload} title="Shift left">UPLOAD</button>
+                            <button className="mobileInterface-button" onClick={e => this.upload(e, false)} title="Upload">UPLOAD</button>
+                            <button className="mobileInterface-button" onClick={e => this.upload(e, true)} title="Upload">UPLOAD AS COLLECTION</button>
                         </div>
                     </div>
                     <DocumentView
diff --git a/src/server/Message.ts b/src/server/Message.ts
index c23a2f0a8..6dac37a46 100644
--- a/src/server/Message.ts
+++ b/src/server/Message.ts
@@ -65,6 +65,7 @@ export interface UpdateMobileInkOverlayPositionContent {
 
 export interface MobileDocumentUploadContent {
     readonly docId: string;
+    readonly asCollection: boolean;
 }
 
 export namespace MessageStore {
-- 
cgit v1.2.3-70-g09d2


From 74ca8ac01e32faa8adab54ddfd806fe46cda03ec Mon Sep 17 00:00:00 2001
From: Hannah <hannah_chow@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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<DropEvent>("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<FieldViewProps, WebDocument>
 
     private _longPressSecondsHack?: NodeJS.Timeout;
     private _iframeRef = React.createRef<HTMLIFrameElement>();
+    private _iframeIndicatorRef = React.createRef<HTMLDivElement>();
     private _iframeDragRef = React.createRef<HTMLDivElement>();
     @observable private _pressX: number = 0;
     @observable private _pressY: number = 0;
@@ -63,39 +64,6 @@ export class WebBox extends DocAnnotatableComponent<FieldViewProps, WebDocument>
     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<FieldViewProps, WebDocument>
         }
     }
 
-    // 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<FieldViewProps, WebDocument>
                 <div className={classname}  >
                     {content}
                 </div>
-                <div className="mobileIframeDragger" ref={this._iframeDragRef} draggable></div>
-                {!frozen ? (null) : <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} />}
-                {/* onPointerDown={(e) => { this.onPrePointer(e); this.onLongPressDown(e) }} onPointerMove={this.onPrePointer} onPointerUp={(e) => { this.onPrePointer(e); }} />} */}
+                {!frozen ? (null) :
+                    <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer}>
+                        <div className="touch-iframe-overlay" onPointerDown={this.onLongPressDown} >
+                            <div className="indicator" ref={this._iframeIndicatorRef}></div>
+                            <div className="dragger" ref={this._iframeDragRef}></div>
+                        </div>
+                    </div>}
             </>);
     }
     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<GestureUtils.GestureEvent>("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}
             >
+                <p>{this._text}</p>
                 <div className="mobileInkOverlay-border top" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border bottom" onPointerDown={this.dragStart}></div>
                 <div className="mobileInkOverlay-border left" onPointerDown={this.dragStart}></div>
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 <DocumentView
                 Document={this.mainContainer}
                 DataDoc={undefined}
                 LibraryPath={emptyPath}
-                addDocument={(doc: Doc) => { 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 {
                             <button className="mobileInterface-button cancel" onClick={this.onBack} title="Back">BACK</button>
                         </div>
                         <div className="uploadSettings">
-                            <button className="mobileInterface-button" onClick={e => this.upload(e, false)} title="Upload">UPLOAD</button>
-                            <button className="mobileInterface-button" onClick={e => this.upload(e, true)} title="Upload">UPLOAD AS COLLECTION</button>
+                            <button className="mobileInterface-button" onClick={this.upload} title="Upload">UPLOAD</button>
                         </div>
                     </div>
                     <DocumentView
                         Document={this.mainContainer}
                         DataDoc={undefined}
                         LibraryPath={emptyPath}
-                        addDocument={(doc: Doc) => { 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 <fangrui_tong@brown.edu>
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/mobile/MobileInkOverlay.tsx')

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<FieldViewProps, WebDocument>
                 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<GestureUtils.GestureEvent>("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

