aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2022-08-09 11:35:00 -0400
committerbobzel <zzzman@gmail.com>2022-08-09 11:35:00 -0400
commitbca0026764fe554e1066b2f432e749371450d239 (patch)
tree8ca81efada997b9eb1e47bc74e1868b35b735e43 /src/client/views/nodes
parentaf0e9bcc4cea84b3f837847143ea8f0a281856df (diff)
added an audio annotation button to the anchor menu bar.
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/DocumentView.tsx35
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx11
2 files changed, 29 insertions, 17 deletions
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 4b2bd07ef..f87581875 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -206,7 +206,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
public static SelectAfterContextMenu = true; // whether a document should be selected after it's contextmenu is triggered.
_animateScaleTime = 300; // milliseconds;
@observable _animateScalingTo = 0;
- @observable _mediaState = 0;
@observable _pendingDoubleClick = false;
private _disposers: { [name: string]: IReactionDisposer } = {};
private _downX: number = 0;
@@ -879,7 +878,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
!appearance && cm.addItem({ description: 'UI Controls...', subitems: appearanceItems, icon: 'compass' });
if (!Doc.IsSystem(this.rootDoc) && this.rootDoc._viewType !== CollectionViewType.Docking && this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Tree) {
- !Doc.noviceMode && appearanceItems.splice(0, 0, { description: `${!this.layoutDoc._showAudio ? 'Show' : 'Hide'} Audio Button`, event: action(() => (this.layoutDoc._showAudio = !this.layoutDoc._showAudio)), icon: 'microphone' });
const existingOnClick = cm.findByDescription('OnClick...');
const onClicks: ContextMenuProps[] = existingOnClick && 'subitems' in existingOnClick ? existingOnClick.subitems : [];
@@ -1010,10 +1008,15 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const audioAnnosCount = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null)?.length;
const audioTextAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations-text'], listSpec('string'), null);
const audioView =
- (!this.props.isSelected() && !this._isHovering) || this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (!audioAnnosCount && !this._mediaState) ? null : (
+ (!this.props.isSelected() && !this._isHovering && this.dataDoc.audioAnnoState !== 2) || this.props.renderDepth === -1 || SnappingManager.GetIsDragging() || (!audioAnnosCount && !this.dataDoc.audioAnnoState) ? null : (
<Tooltip title={<div>{audioTextAnnos?.lastElement()}</div>}>
<div className="documentView-audioBackground" onPointerDown={this.playAnnotation}>
- <FontAwesomeIcon className="documentView-audioFont" style={{ color: [audioAnnosCount ? 'blue' : 'gray', 'green', 'red'][this._mediaState] }} icon={!audioAnnosCount ? 'microphone' : 'file-audio'} size="sm" />
+ <FontAwesomeIcon
+ className="documentView-audioFont"
+ style={{ color: [audioAnnosCount ? 'blue' : 'gray', 'green', 'red'][NumCast(this.dataDoc.audioAnnoState)] }}
+ icon={!audioAnnosCount ? 'microphone' : 'file-audio'}
+ size="sm"
+ />
</div>
</Tooltip>
);
@@ -1154,7 +1157,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const self = this;
const audioAnnos = Cast(this.dataDoc[this.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null);
const anno = audioAnnos.lastElement();
- if (anno instanceof AudioField && this._mediaState === 0) {
+ if (anno instanceof AudioField && this.dataDoc.audioAnnoState === 0) {
new Howl({
src: [anno.url.href],
format: ['mp3'],
@@ -1163,27 +1166,25 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
volume: 0.5,
onend: function () {
runInAction(() => {
- console.log('PLAYED');
- self._mediaState = 0;
+ self.dataDoc.audioAnnoState = 0;
});
},
});
- this._mediaState = 1;
+ this.dataDoc.audioAnnoState = 1;
}
};
- recordAudioAnnotation = (onEnd?: () => void) => {
+ static recordAudioAnnotation(dataDoc: Doc, field: string, onEnd?: () => void) {
let gumStream: any;
let recorder: any;
- const self = this;
navigator.mediaDevices
.getUserMedia({
audio: true,
})
.then(function (stream) {
- let audioTextAnnos = Cast(self.dataDoc[self.LayoutFieldKey + '-audioAnnotations-text'], listSpec('string'), null);
+ let audioTextAnnos = Cast(dataDoc[field + '-audioAnnotations-text'], listSpec('string'), null);
if (audioTextAnnos) audioTextAnnos.push('');
- else audioTextAnnos = self.dataDoc[self.LayoutFieldKey + '-audioAnnotations-text'] = new List<string>(['']);
+ else audioTextAnnos = dataDoc[field + '-audioAnnotations-text'] = new List<string>(['']);
DictationManager.Controls.listen({
interimHandler: value => (audioTextAnnos[audioTextAnnos.length - 1] = value),
continuous: { indefinite: false },
@@ -1200,24 +1201,24 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
const [{ result }] = await Networking.UploadFilesToServer(e.data);
if (!(result instanceof Error)) {
const audioField = new AudioField(result.accessPaths.agnostic.client);
- const audioAnnos = Cast(self.dataDoc[self.LayoutFieldKey + '-audioAnnotations'], listSpec(AudioField), null);
+ const audioAnnos = Cast(dataDoc[field + '-audioAnnotations'], listSpec(AudioField), null);
if (audioAnnos === undefined) {
- self.dataDoc[self.LayoutFieldKey + '-audioAnnotations'] = new List([audioField]);
+ dataDoc[field + '-audioAnnotations'] = new List([audioField]);
} else {
audioAnnos.push(audioField);
}
}
};
- runInAction(() => (self._mediaState = 2));
+ runInAction(() => (dataDoc.audioAnnoState = 2));
recorder.start();
setTimeout(() => {
recorder.stop();
DictationManager.Controls.stop(false);
- runInAction(() => (self._mediaState = 0));
+ runInAction(() => (dataDoc.audioAnnoState = 0));
gumStream.getAudioTracks()[0].stop();
}, 5000);
});
- };
+ }
captionStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewInternalProps>, property: string) => this.props?.styleProvider?.(doc, props, property + ':caption');
@computed get innards() {
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 929cca1ea..223441b3b 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -63,6 +63,7 @@ import applyDevTools = require('prosemirror-dev-tools');
import React = require('react');
import { text } from 'body-parser';
import { CollectionTreeView } from '../../collections/CollectionTreeView';
+import { DocumentViewInternal } from '../DocumentView';
const translateGoogleApi = require('translate-google-api');
export interface FormattedTextBoxProps {
@@ -249,6 +250,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
!this.layoutDoc.showSidebar && this.toggleSidebar();
this._sidebarRef.current?.anchorMenuClick(this.getAnchor());
};
+ AnchorMenu.Instance.OnAudio = (e: PointerEvent) => {
+ !this.layoutDoc.showSidebar && this.toggleSidebar();
+ const anchor = this.getAnchor();
+ const target = this._sidebarRef.current?.anchorMenuClick(anchor);
+ if (target) {
+ anchor.followLinkAudio = true;
+ DocumentViewInternal.recordAudioAnnotation(Doc.GetProto(target), Doc.LayoutFieldKey(target));
+ target.title = ComputedField.MakeFunction(`self["text-audioAnnotations-text"].lastElement()`);
+ }
+ };
AnchorMenu.Instance.Highlight = action((color: string, isLinkButton: boolean) => {
this._editorView?.state && RichTextMenu.Instance.setHighlight(color, this._editorView, this._editorView?.dispatch);
return undefined;