aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/IconTagBox.tsx
blob: d04ec3a10b557a8642a457a447ef1de92457508e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { computed, makeObservable } from 'mobx';
import { observer } from 'mobx-react';
import React from 'react';
import { Doc, StrListCast } from '../../../fields/Doc';
import { StrCast } from '../../../fields/Types';
import { AudioAnnoState } from '../../../server/SharedMediaTypes';
import { undoable } from '../../util/UndoManager';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { TagItem } from '../TagsView';
import { DocumentView } from './DocumentView';
import './IconTagBox.scss';
import { Size, Toggle, ToggleType, Type } from '@dash/components';
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { StyleProp } from '../StyleProp';

export interface IconTagProps {
    Views: DocumentView[];
    IsEditing: boolean | undefined;
}

/**
 * Renders the icon tags that rest under the document. The icons rendered are determined by the values of
 * each icon in the userdoc.
 */
@observer
export class IconTagBox extends ObservableReactComponent<IconTagProps> {
    constructor(props: IconTagProps) {
        super(props);
        makeObservable(this);
    }

    @computed get View() { return this._props.Views.lastElement(); } // prettier-ignore
    @computed get currentScale() { return this.View?.screenToLocalScale(); } // prettier-ignore

    /**
     * Sets or removes the specified tag
     * @param tag tag name (should begin with '#')
     * @param state flag to add or remove the metadata
     */
    setIconTag = undoable((tag: string, state: boolean) => {
        this._props.Views.forEach(view => {
            state && TagItem.addTagToDoc(view.dataDoc, tag);
            !state && TagItem.removeTagFromDoc(view.dataDoc, tag);
        });
    }, 'toggle card tag');

    /**
     * Returns a renderable version of the button Doc that is colorized to indicate
     * whether the doc has the associated tag set on it or not.
     * @param doc doc to test
     * @param key metadata icon button
     * @returns an icon for the metdata button
     */
    getButtonIcon = (dv: DocumentView, key: Doc): JSX.Element => {
        const icon = StrCast(key.icon) as IconProp;
        const tag = StrCast(key.toolType);
        const color = dv._props.styleProvider?.(dv.layoutDoc, dv.ComponentView?._props, StyleProp.FontColor) as string;
        return (
            <div>
                {' '}
                {/* tooltips require the wrapped item to be an element ref */}
                <Toggle
                    tooltip={`Click to add/remove the tag ${tag}`}
                    toggleStatus={TagItem.docHasTag(dv.Document, tag)}
                    toggleType={ToggleType.BUTTON}
                    icon={<FontAwesomeIcon className={`fontIconBox-icon-${ToggleType.BUTTON}`} icon={icon} color={color} />}
                    size={Size.XSMALL}
                    type={Type.PRIM}
                    onClick={() => this.setIconTag(tag, !TagItem.docHasTag(this.View.Document, tag))}
                    color={color}
                />
            </div>
        );
    };

    /**
     * Displays a button to play audio annotations on the document.
     * NOTE: This should be generalized  --  audio should
     * @returns
     */
    renderAudioButtons = (dv: DocumentView, anno: string) => {
        const fcolor = dv._props.styleProvider?.(dv.layoutDoc, dv.ComponentView?._props, StyleProp.FontColor) as string;
        const audioIconColors: { [key: string]: string } = { playing: 'green', stopped: fcolor ?? 'blue', recording: 'red' };
        const audioAnnoState = (audioDoc: Doc) => StrCast(audioDoc.audioAnnoState, AudioAnnoState.stopped);
        const color = audioIconColors[audioAnnoState(this.View.Document)];
        return (
            <Toggle
                tooltip={`click to play:${anno}`}
                toggleStatus={true}
                toggleType={ToggleType.BUTTON}
                icon={<FontAwesomeIcon className={`fontIconBox-icon-${ToggleType.BUTTON}`} icon="file-audio" color={color} />}
                size={Size.XSMALL}
                type={Type.PRIM}
                onClick={() => this.View?.playAnnotation()}
                color={color}
            />
        );
    };

    /**
     * Renders the buttons to customize sorting depending on which group the card belongs to and the amount of total groups
     */
    render() {
        const buttons = Doc.MyFilterHotKeys 
            .map(key => ({ key, tag: StrCast(key.toolType) }))
            .filter(({ tag }) => this._props.IsEditing || TagItem.docHasTag(this.View.Document, tag) || (DocumentView.Selected().length === 1 && this.View.IsSelected))
            .map(({ key, tag }) => (
                <Tooltip key={tag} title={<div className="dash-tooltip">Click to add/remove the {tag} tag</div>}>
                    {this.getButtonIcon(this.View, key)}
                </Tooltip>
            )); // prettier-ignore

        const audioannos = StrListCast(this.View.Document[Doc.LayoutDataKey(this.View.Document) + '_audioAnnotations_text']);
        return !buttons.length && !audioannos.length ? null : (
            <div className="card-button-container" style={{ fontSize: '50px' }}>
                {audioannos.length ? this.renderAudioButtons(this.View, audioannos.lastElement()) : null}
                {buttons}
            </div>
        );
    }
}