diff options
Diffstat (limited to 'src')
6 files changed, 123 insertions, 96 deletions
diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index ff471853a..1e4c120bc 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -153,21 +153,20 @@ export namespace GooglePhotos { } const tagMapping = new Map<string, string>(); const images = (await DocListCastAsync(collection.data))!.map(Doc.GetProto); - images && images.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE)); - const values = Object.values(ContentCategories); + images?.forEach(image => tagMapping.set(image[Id], ContentCategories.NONE)); + const values = Object.values(ContentCategories).filter(value => value !== ContentCategories.NONE); for (const value of values) { - if (value === ContentCategories.NONE) { - continue; - } - for (const id of (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id)) { + const searched = (await ContentSearch({ included: [value] }))?.mediaItems?.map(({ id }) => id); + console.log("Searching " + value); + console.log(searched); + searched?.forEach(async id => { const image = await Cast(idMapping[id], Doc); - if (!image) { - continue; + if (image) { + const key = image[Id]; + const tags = tagMapping.get(key); + !tags?.includes(value) && tagMapping.set(key, tags + delimiter + value); } - const key = image[Id]; - const tags = tagMapping.get(key); - !tags?.includes(value) && tagMapping.set(key, tags + delimiter + value); - } + }); } images?.forEach(image => { const concatenated = tagMapping.get(image[Id])!; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8c78e568c..250c9b3b0 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, ScriptCast } from "../../../new_fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Upload } from "../../../server/SharedMediaTypes"; @@ -208,19 +208,18 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { const docDragData = de.complete.docDragData; - (this.props.Document.dropConverter instanceof ScriptField) && - this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this + ScriptCast(this.props.Document.dropConverter)?.script.run({ dragData: docDragData }); if (docDragData) { let added = false; if (docDragData.dropAction || docDragData.userDropAction) { - added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); + added = this.props.addDocument(docDragData.droppedDocuments as any as Doc); } else if (docDragData.moveDocument) { - const movedDocs = docDragData.draggedDocuments; - added = movedDocs.reduce((added: boolean, d, i) => - docDragData.droppedDocuments[i] !== d ? this.props.addDocument(docDragData.droppedDocuments[i]) : - docDragData.moveDocument?.(d, this.props.Document, this.props.addDocument) || added, false); + const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); + const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); + const res = addedDocs.length ? this.props.addDocument(addedDocs as any as Doc) : true; + added = movedDocs.length ? docDragData.moveDocument(movedDocs as any as Doc, this.props.Document, this.props.addDocument) : res; } else { - added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false); + added = this.props.addDocument(docDragData.droppedDocuments as any as Doc); } e.stopPropagation(); return added; @@ -389,8 +388,13 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: console.log(result); const json = JSON.parse(result as string) as any; addDocument(Docs.Create.TreeDocument( - json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => - Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }) + json["rectangular-puzzle"].crossword.clues[0].clue.map((c: any) => { + const label = Docs.Create.LabelDocument({ title: c["#text"], _width: 120, _height: 20 }); + const proto = Doc.GetProto(label) + proto._width = 120; + proto._height = 20; + return proto; + } ), { _width: 150, _height: 600, title: "across", backgroundColor: "white", _singleLine: true })); }); } diff --git a/src/client/views/collections/CollectionView.scss b/src/client/views/collections/CollectionView.scss index d43dd387a..7877fe155 100644 --- a/src/client/views/collections/CollectionView.scss +++ b/src/client/views/collections/CollectionView.scss @@ -70,7 +70,7 @@ height: 30px; position: absolute; bottom: 15px; - left: 15px; + right: 15px; border: 2px solid black; border-radius: 50%; padding: 3px; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 43da1c44f..ccfc660cc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -15,9 +15,7 @@ import { ImageField } from '../../../new_fields/URLField'; import { TraceMobx } from '../../../new_fields/util'; import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; -import { DocumentManager } from '../../util/DocumentManager'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; -import { SelectionManager } from '../../util/SelectionManager'; import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from '../nodes/FieldView'; import { ScriptBox } from '../ScriptBox'; @@ -45,7 +43,6 @@ import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; import { ObjectField } from '../../../new_fields/ObjectField'; import CollectionMapView from './CollectionMapView'; -import { Transform } from 'prosemirror-transform'; import { CollectionPileView } from './CollectionPileView'; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; @@ -119,35 +116,32 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus whenActiveChanged = (isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive); @action.bound - addDocument(doc: Doc): boolean { - if (this.props.filterAddDocument?.(doc) === false) { - return false; + addDocument = (doc: Doc): boolean => { + if (doc instanceof Doc) { + if (this.props.filterAddDocument?.(doc) === false) { + return false; + } } - + const docs = doc instanceof Doc ? [doc] : doc as any as Doc[]; const targetDataDoc = this.props.Document[DataSym]; const docList = DocListCast(targetDataDoc[this.props.fieldKey]); - !docList.includes(doc) && (targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, doc])); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there - // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); - doc.context = this.props.Document; - Doc.GetProto(doc).lastOpened = new DateField; + const added = docs.filter(d => !docList.includes(d)); + if (added.length) { + added.map(doc => doc.context = this.props.Document); + targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } return true; } @action.bound - removeDocument(doc: Doc): boolean { + removeDocument = (doc: any): boolean => { + const docs = doc instanceof Doc ? [doc] : doc as Doc[]; const targetDataDoc = this.props.Document[DataSym]; - const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); - docView && SelectionManager.DeselectDoc(docView); const value = DocListCast(targetDataDoc[this.props.fieldKey]); - 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); - - doc.context = undefined; - ContextMenu.Instance?.clearItems(); - if (index !== -1) { - value.splice(index, 1); - targetDataDoc[this.props.fieldKey] = new List<Doc>(value); + const result = value.filter(v => !docs.includes(v)); + if (result.length !== value.length) { + targetDataDoc[this.props.fieldKey] = new List<Doc>(result); return true; } return false; @@ -158,7 +152,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus // otherwise, the document being moved must be able to be removed from its container before // moving it into the target. @action.bound - moveDocument(doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean { + moveDocument = (doc: Doc, targetCollection: Doc | undefined, addDocument: (doc: Doc) => boolean): boolean => { if (Doc.AreProtosEqual(this.props.Document, targetCollection)) { return true; } @@ -166,10 +160,14 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus } showIsTagged = () => { - const children = DocListCast(this.props.Document[this.props.fieldKey]); - const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); - const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); - return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />; + return (null); + // this section would display an icon in the bototm right of a collection to indicate that all + // photos had been processed through Google's content analysis API and Google's tags had been + // assigned to the documents googlePhotosTags field. + // const children = DocListCast(this.props.Document[this.props.fieldKey]); + // const imageProtos = children.filter(doc => Cast(doc.data, ImageField)).map(Doc.GetProto); + // const allTagged = imageProtos.length > 0 && imageProtos.every(image => image.googlePhotosTags); + // return !allTagged ? (null) : <img id={"google-tags"} src={"/assets/google_tags.png"} />; } private SubViewHelper = (type: CollectionViewType, renderProps: CollectionRenderProps) => { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 37957b0f6..6011d5f9c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -124,10 +124,15 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P this.addDocument(newBox); } private addDocument = (newBox: Doc) => { - const added = this.props.addDocument(newBox); - added && this.bringToFront(newBox); - added && this.updateCluster(newBox); - return added; + if (newBox instanceof Doc) { + const added = this.props.addDocument(newBox); + added && this.bringToFront(newBox); + added && this.updateCluster(newBox); + return added; + } else { + return this.props.addDocument(newBox); + // bcz: deal with clusters + } } private selectDocuments = (docs: Doc[]) => { SelectionManager.DeselectAll(); @@ -153,6 +158,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const xfo = this.getTransformOverlay(); const [xp, yp] = xf.transformPoint(de.x, de.y); const [xpo, ypo] = xfo.transformPoint(de.x, de.y); + const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); if (super.onInternalDrop(e, de)) { if (de.complete.docDragData) { if (de.complete.docDragData.droppedDocuments.length) { @@ -162,20 +168,25 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const y = (z ? ypo : yp) - de.complete.docDragData.offset[1]; const dropX = NumCast(firstDoc.x); const dropY = NumCast(firstDoc.y); - de.complete.docDragData.droppedDocuments.forEach(action((d: Doc) => { - const layoutDoc = Doc.Layout(d); - d.x = x + NumCast(d.x) - dropX; - d.y = y + NumCast(d.y) - dropY; - if (!NumCast(layoutDoc._width)) { - layoutDoc._width = 300; - } - if (!NumCast(layoutDoc._height)) { - const nw = NumCast(layoutDoc._nativeWidth); - const nh = NumCast(layoutDoc._nativeHeight); - layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300; + const droppedDocs = de.complete.docDragData.droppedDocuments; + runInAction(() => { + zsorted.forEach((doc, index) => doc.zIndex = index + 1); + for (let i = 0; i < droppedDocs.length; i++) { + const d = droppedDocs[i]; + const layoutDoc = Doc.Layout(d); + d.x = x + NumCast(d.x) - dropX; + d.y = y + NumCast(d.y) - dropY; + if (!NumCast(layoutDoc._width)) { + layoutDoc._width = 300; + } + if (!NumCast(layoutDoc._height)) { + const nw = NumCast(layoutDoc._nativeWidth); + const nh = NumCast(layoutDoc._nativeHeight); + layoutDoc._height = nw && nh ? nh / nw * NumCast(layoutDoc._width) : 300; + } + d.isBackground === undefined && (d.zIndex = zsorted.length + 1 + i); } - d.isBackground === undefined && this.bringToFront(d); - })); + }); (de.complete.docDragData.droppedDocuments.length === 1 || de.shiftKey) && this.updateClusterDocs(de.complete.docDragData.droppedDocuments); } @@ -760,20 +771,21 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } } - bringToFront = (doc: Doc, sendToBack?: boolean) => { + bringToFront = action((doc: Doc, sendToBack?: boolean) => { if (sendToBack || doc.isBackground) { doc.zIndex = 0; } else { const docs = this.childLayoutPairs.map(pair => pair.layout); - docs.slice().sort((doc1, doc2) => { - if (doc1 === doc) return 1; - if (doc2 === doc) return -1; - return NumCast(doc1.zIndex) - NumCast(doc2.zIndex); - }).forEach((doc, index) => doc.zIndex = index + 1); - doc.zIndex = docs.length + 1; + docs.slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex)); + let zlast = docs.length ? NumCast(docs[docs.length - 1].zIndex) : 1; + if (zlast - docs.length > 100) { + for (let i = 0; i < docs.length; i++) doc.zIndex = i + 1; + zlast = docs.length + 1; + } + doc.zIndex = zlast + 1; } - } + }) scaleAtPt(docpt: number[], scale: number) { const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]); @@ -895,14 +907,22 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P addDocTab = action((doc: Doc, where: string) => { if (where === "inParent") { - const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); - doc.x = pt[0]; - doc.y = pt[1]; - this.props.addDocument(doc); - return true; + if (doc instanceof Doc) { + const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); + doc.x = pt[0]; + doc.y = pt[1]; + return this.props.addDocument(doc); + } else { + (doc as any as Doc[]).forEach(doc => { + const pt = this.getTransform().transformPoint(NumCast(doc.x), NumCast(doc.y)); + doc.x = pt[0]; + doc.y = pt[1]; + }); + return this.props.addDocument(doc); + } } if (where === "inPlace" && this.layoutDoc.isInPlaceContainer) { - this.dataDoc[this.props.fieldKey] = new List<Doc>([doc]); + this.dataDoc[this.props.fieldKey] = doc instanceof Doc ? doc : new List<Doc>(doc as any as Doc[]); return true; } return this.props.addDocTab(doc, where); @@ -1002,8 +1022,10 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; - runInAction(() => - Array.from(newPool.entries()).map(entry => { + const array = Array.from(newPool.entries()); + runInAction(() => { + for (let i = 0; i < array.length; i++) { + const entry = array[i]; const lastPos = this._cachedPool.get(entry[0]); // last computed pos const newPos = entry[1]; if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) { @@ -1012,7 +1034,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P if (!lastPos || newPos.height !== lastPos.height || newPos.width !== lastPos.width) { this._layoutSizeData.set(entry[0], { width: newPos.width, height: newPos.height }); } - })); + } + }); this._cachedPool.clear(); Array.from(newPool.entries()).forEach(k => this._cachedPool.set(k[0], k[1])); const elements: ViewDefResult[] = computedElementData.slice(); @@ -1058,12 +1081,13 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } promoteCollection = undoBatch(action(() => { - this.childDocs.forEach(doc => { + const childDocs = this.childDocs.slice(); + childDocs.forEach(doc => { const scr = this.getTransform().inverse().transformPoint(NumCast(doc.x), NumCast(doc.y)); doc.x = scr?.[0]; doc.y = scr?.[1]; - this.props.addDocTab(doc, "inParent") && this.props.removeDocument(doc); }); + this.props.addDocTab(childDocs as any as Doc, "inParent"); this.props.ContainingCollectionView?.removeDocument(this.props.Document); })); layoutDocsInGrid = () => { @@ -1148,6 +1172,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P @action setupDragLines = () => { + const activeDocs = this.getActiveDocuments(); + if (activeDocs.length > 50) { + DragManager.SetSnapLines([], []); + return; + } const size = this.props.ScreenToLocalTransform().transformDirection(this.props.PanelWidth(), this.props.PanelHeight()); const selRect = { left: this.panX() - size[0] / 2, top: this.panY() - size[1] / 2, width: size[0], height: size[1] }; const docDims = (doc: Doc) => ({ left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(doc._width), height: NumCast(doc._height) }); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 5bac075b4..43d4203ad 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -198,7 +198,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque @action onPointerUp = (e: PointerEvent): void => { - if (!this.props.active(true)) this.props.selectDocuments([this.props.Document], []); if (this._visible) { const mselect = this.marqueeSelect(); if (!e.shiftKey) { @@ -300,10 +299,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque @action delete = () => { - this.marqueeSelect(false).map(d => this.props.removeDocument(d)); - if (this.ink) { - // this.marqueeInkDelete(this.ink.inkData); - } + this.props.removeDocument(this.marqueeSelect(false) as any as Doc); SelectionManager.DeselectAll(); this.cleanupInteractions(false); MarqueeOptionsMenu.Instance.fadeOut(true); @@ -349,13 +345,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque const bounds = this.Bounds; const selected = this.marqueeSelect(false); if (e instanceof KeyboardEvent ? e.key === "c" : true) { - selected.map(d => { - this.props.removeDocument(d); + selected.map(action(d => { + //this.props.removeDocument(d); d.x = NumCast(d.x) - bounds.left - bounds.width / 2; d.y = NumCast(d.y) - bounds.top - bounds.height / 2; d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection return d; - }); + })); + this.props.removeDocument(selected as any as Doc); } const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined); this.props.addDocument(newCollection); |