From d12b43191e01e837d5a144fb19d9d3cd8eadd777 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 26 Aug 2024 15:17:14 -0400
Subject: from last

---
 .../collectionFreeForm/FaceCollectionBox.tsx       | 60 ++++++++++++++--------
 1 file changed, 40 insertions(+), 20 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
index 6a0d51e32..33fc3c210 100644
--- a/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
+++ b/src/client/views/collections/collectionFreeForm/FaceCollectionBox.tsx
@@ -3,14 +3,14 @@ import { IconButton, Size } from 'browndash-components';
 import * as faceapi from 'face-api.js';
 import { FaceMatcher } from 'face-api.js';
 import 'ldrs/ring';
-import { action, makeObservable, observable } from 'mobx';
+import { IReactionDisposer, action, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import React from 'react';
-import { lightOrDark, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils';
+import { DivHeight, lightOrDark, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils';
 import { emptyFunction } from '../../../../Utils';
 import { Doc, Opt } from '../../../../fields/Doc';
 import { List } from '../../../../fields/List';
-import { ImageCast, StrCast } from '../../../../fields/Types';
+import { ImageCast, NumCast, StrCast } from '../../../../fields/Types';
 import { DocumentType } from '../../../documents/DocumentTypes';
 import { Docs } from '../../../documents/Documents';
 import { DragManager } from '../../../util/DragManager';
@@ -48,10 +48,29 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
         super(props);
         makeObservable(this);
     }
+    @observable _headerRef: HTMLDivElement | null = null;
+    @observable _listRef: HTMLDivElement | null = null;
+    _disposers: { [key: string]: IReactionDisposer } = {};
+    _lastHeight = 0;
+    observer = new ResizeObserver(() => this._props.setHeight?.((this.props.Document._face_showImages ? 20 : 0) + (!this._headerRef ? 0 : DivHeight(this._headerRef)) + (!this._listRef ? 0 : DivHeight(this._listRef))));
+
+    componentDidMount(): void {
+        this._disposers.refList = reaction(
+            () => ({ refList: [this._headerRef, this._listRef], autoHeight: this.layoutDoc._layout_autoHeight && !DocumentView.LightboxContains(this.DocumentView?.()) }),
+            ({ refList, autoHeight }) => {
+                this.observer.disconnect();
+                if (autoHeight) refList.filter(r => r).forEach(r => this.observer.observe(r!));
+            },
+            { fireImmediately: true }
+        );
+    }
 
+    componentWillUnmount(): void {
+        //this._disposers?.();
+    }
     protected createDropTarget = (ele: HTMLDivElement) => {
         this._dropDisposer?.();
-        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this._props.Document));
+        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this), this.Document));
     };
 
     protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
@@ -59,12 +78,12 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
             ?.filter(doc => doc.type === DocumentType.IMG)
             .forEach(imgDoc => {
                 // If the current Face Document has no faces, and the doc has more than one face descriptor, don't let the user add the document first.  Or should we just use the first face ?
-                if (FaceRecognitionHandler.UniqueFaceDescriptors(this._props.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) {
+                if (FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).length === 0 && FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).length > 1) {
                     alert('Cannot add a document with multiple faces as the first item!');
                 } else {
                     // Loop through the documents' face descriptors and choose the face in the iage with the smallest distance (most similar to the face colleciton)
-                    const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this._props.Document).map(fd => new Float32Array(Array.from(fd)));
-                    const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this._props.Document), faceDescriptorsAsFloat32Array);
+                    const faceDescriptorsAsFloat32Array = FaceRecognitionHandler.UniqueFaceDescriptors(this.Document).map(fd => new Float32Array(Array.from(fd)));
+                    const labeledFaceDescriptor = new faceapi.LabeledFaceDescriptors(FaceRecognitionHandler.UniqueFaceLabel(this.Document), faceDescriptorsAsFloat32Array);
                     const faceMatcher = new FaceMatcher([labeledFaceDescriptor], 1);
                     const { face_match } = FaceRecognitionHandler.ImageDocFaceDescriptors(imgDoc).reduce(
                         (prev, face) => {
@@ -76,7 +95,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
 
                     // assign the face in the image that's closest to the face collection to be the face that's assigned to the collection
                     if (face_match) {
-                        FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this._props.Document);
+                        FaceRecognitionHandler.UniqueFaceAddFaceImage(imgDoc, face_match, this.Document);
                     }
                 }
             });
@@ -87,17 +106,17 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
     /**
      * Toggles whether a Face Document displays its associated docs.
      */
-    @action
     onDisplayClick() {
-        this._props.Document._displayImages = !this.props.Document._displayImages;
-        this._props.Document.height = this._props.Document._displayImages ? 400 : 100;
+        this.Document._face_showImages && (this._lastHeight = NumCast(this.Document.height));
+        this.Document._face_showImages = !this.Document._face_showImages;
+        setTimeout(action(() => (!this.Document.layout_autoHeight || !this.Document._face_showImages) && (this.Document.height = this.Document._face_showImages ? this._lastHeight : 60)));
     }
 
     /**
      * Removes a unique face Doc from the colelction of unique faces.
      */
     deleteUniqueFace = undoable(() => {
-        FaceRecognitionHandler.DeleteUniqueFace(this._props.Document);
+        FaceRecognitionHandler.DeleteUniqueFace(this.Document);
     }, 'delete face');
 
     /**
@@ -105,7 +124,7 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
      * @param imgDoc - image Doc to remove
      */
     removeFaceImageFromUniqueFace = undoable((imgDoc: Doc) => {
-        FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this._props.Document);
+        FaceRecognitionHandler.UniqueFaceRemoveFaceImage(imgDoc, this.Document);
     }, 'remove doc from face');
 
     onPassiveWheel = (e: WheelEvent) => e.stopPropagation();
@@ -116,31 +135,32 @@ export class UniqueFaceBox extends ViewBoxBaseComponent<FieldViewProps>() {
                 <div className="face-collection-buttons">
                     <IconButton tooltip="Delete Face From Collection" onPointerDown={this.deleteUniqueFace} icon={'x'} style={{ width: '4px' }} size={Size.XSMALL} />
                 </div>
-                <div className="face-document-top">
-                    <h1 style={{ color: lightOrDark(StrCast(this._props.Document.backgroundColor)) }}>{FaceRecognitionHandler.UniqueFaceLabel(this._props.Document)}</h1>
+                <div className="face-document-top" ref={action((r: HTMLDivElement | null) => (this._headerRef = r))}>
+                    <h1 style={{ color: lightOrDark(StrCast(this.Document.backgroundColor)) }}>{FaceRecognitionHandler.UniqueFaceLabel(this.Document)}</h1>
                 </div>
                 <div className="face-collection-toggle">
                     <IconButton
                         tooltip="See image information"
                         onPointerDown={() => this.onDisplayClick()}
-                        icon={<FontAwesomeIcon icon={this._props.Document._displayImages ? 'caret-up' : 'caret-down'} />}
+                        icon={<FontAwesomeIcon icon={this.Document._face_showImages ? 'caret-up' : 'caret-down'} />}
                         color={MarqueeOptionsMenu.Instance.userColor}
                         style={{ width: '19px' }}
                     />
                 </div>
-                {this.props.Document._displayImages ? (
+                {this.props.Document._face_showImages ? (
                     <div
                         className="face-document-image-container"
                         style={{
                             pointerEvents: this._props.isContentActive() ? undefined : 'none',
                         }}
-                        ref={ele => {
+                        ref={action((ele: HTMLDivElement | null) => {
+                            this._listRef = ele;
                             this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
                             this._oldWheel = ele;
                             // prevent wheel events from passively propagating up through containers and prevents containers from preventDefault which would block scrolling
                             ele?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
-                        }}>
-                        {FaceRecognitionHandler.UniqueFaceImages(this._props.Document).map((doc, i) => {
+                        })}>
+                        {FaceRecognitionHandler.UniqueFaceImages(this.Document).map((doc, i) => {
                             const [name, type] = ImageCast(doc[Doc.LayoutFieldKey(doc)]).url.href.split('.');
                             return (
                                 <div
-- 
cgit v1.2.3-70-g09d2

