import React, { PureComponent } from 'react' import { connect } from 'react-redux' import actions from 'app/actions' import { ZOOM_STEPS, INNER_HEIGHT } from 'app/constants' import { clamp } from 'app/utils' import { positionToTime, timeToPosition } from 'app/utils/align.utils' import { AnnotationElementLookup } from './annotationTypes' class AnnotationIndex extends PureComponent { state = { items: [], } constructor(props){ super(props) this.handleClick = this.handleClick.bind(this) } componentDidUpdate(prevProps) { if (this.props.index.loading) return if (prevProps.timeline !== this.props.timeline || prevProps.index !== this.props.index) { this.update() } } update() { let { timeline, index } = this.props let { start_ts, zoom, duration } = this.props.timeline const { order, lookup } = index let secondsPerPixel = ZOOM_STEPS[zoom] * 0.1 // 0.1 sec / step let widthTimeDuration = INNER_HEIGHT * secondsPerPixel // secs per pixel let timeMin = start_ts - 60.0 let timeMax = Math.min(start_ts + widthTimeDuration, duration) const items = order.filter(id => { const { start_ts: ts } = lookup[id] return (timeMin < ts && ts < timeMax) }).map(id => lookup[id]) this.setState({ items }) } handleClick(e, annotation) { e.stopPropagation() if (!annotation) return if (e.shiftKey) { e.preventDefault() this.handleParagraphSelection(annotation, e.metaKey) } actions.audio.seek(annotation.start_ts) actions.align.setSelectedAnnotation(annotation) } handleParagraphSelection(annotation, shouldClear) { const { selected_paragraph_id } = this.props.timeline if (!selected_paragraph_id || selected_paragraph_id === -1 || shouldClear) { if (annotation.paragraph_id && !shouldClear) { actions.align.setSelectedParagraph(annotation.paragraph_id) } else { actions.paragraph.create({ type: 'paragraph', episode_id: this.props.episode_id, start_ts: annotation.start_ts, }).then(data => { actions.align.setSelectedParagraph(data.res.id) annotation.paragraph_id = data.res.id actions.annotation.update(annotation) }) } } else if (selected_paragraph_id !== annotation.paragraph_id) { annotation.paragraph_id = selected_paragraph_id actions.annotation.update(annotation) } } handleDoubleClick(e, annotation) { e.stopPropagation() actions.align.showEditAnnotationForm(annotation) } render() { const { timeline, media, annotationInForm, selectedAnnotation } = this.props const { start_ts, zoom, selected_annotation_id } = timeline const { items } = this.state const className = (zoom < 2) ? 'annotationIndex' : (zoom < 3) ? 'annotationIndex condensed' : 'annotationIndex collapsed' return (
{items.map(annotation => { if (annotationInForm && annotation.id === annotationInForm.id) { return null } if (annotation.id === selected_annotation_id) { annotation = selectedAnnotation } const { id, type, start_ts } = annotation const AnnotationElement = AnnotationElementLookup[type] const y = timeToPosition(start_ts, timeline) return ( ) })}
) } } const mapStateToProps = state => ({ timeline: state.align.timeline, annotationInForm: state.align.annotation, selectedAnnotation: state.align.selectedAnnotation, index: state.annotation.index, media: state.media.index.lookup, episode_id: state.site.episode.id, }) export default connect(mapStateToProps)(AnnotationIndex)