summaryrefslogtreecommitdiff
path: root/frontend/site/viewer/viewer.container.js
diff options
context:
space:
mode:
authorlens <lens@neural.garden>2021-03-23 21:10:11 +0000
committerlens <lens@neural.garden>2021-03-23 21:10:11 +0000
commitcc1d0c52e104245f9f1c0d77eb24a5a33800be38 (patch)
tree02d8483dfe47803525b926a43c582dcfbf61c5db /frontend/site/viewer/viewer.container.js
parent81c673f058fda04b96baae7b2302f876479bc0a9 (diff)
parent7a3ec205e001e4c071a67ecc5c375612fa72afdc (diff)
Merge branch 'master' of asdf.us:swimmer
Diffstat (limited to 'frontend/site/viewer/viewer.container.js')
-rw-r--r--frontend/site/viewer/viewer.container.js223
1 files changed, 223 insertions, 0 deletions
diff --git a/frontend/site/viewer/viewer.container.js b/frontend/site/viewer/viewer.container.js
new file mode 100644
index 0000000..9bf4442
--- /dev/null
+++ b/frontend/site/viewer/viewer.container.js
@@ -0,0 +1,223 @@
+import React, { Component } from 'react'
+import { Route } from 'react-router-dom'
+import { bindActionCreators } from 'redux'
+import { connect } from 'react-redux'
+
+import { history } from 'site/store'
+import actions from 'site/actions'
+import { Loader } from 'app/common/loader.component'
+import TileHandle from 'app/views/tile/components/tile.handle'
+
+import 'app/views/page/page.css'
+
+class ViewerContainer extends Component {
+ state = {
+ page: {},
+ bounds: { width: window.innerWidth, height: window.innerHeight },
+ roadblock: false,
+ popups: {},
+ hidden: {},
+ time: 0,
+ maxDeferTime: 0,
+ }
+
+ constructor(props) {
+ super(props)
+ this.pageRef = React.createRef()
+ this.handleMouseDown = this.handleMouseDown.bind(this)
+ this.handleResize = this.handleResize.bind(this)
+ this.removeRoadblock = this.removeRoadblock.bind(this)
+ this.updateTimer = this.updateTimer.bind(this)
+ window.addEventListener('resize', this.handleResize)
+ }
+
+ componentDidUpdate(prevProps) {
+ // console.log('didUpdate', this.props.graph !== prevProps.graph, this.props.location.pathname !== prevProps.location.pathname)
+ if (this.props.graph !== prevProps.graph || this.props.location.pathname !== prevProps.location.pathname) {
+ this.load()
+ }
+ }
+
+ componentWillUnmount() {
+ window.removeEventListener('resize', this.handleResize)
+ actions.site.interact()
+ }
+
+ load() {
+ const { graph_name, page_name } = this.props.match.params
+ const page_path = ["", graph_name, page_name].join('/')
+ const { pages, home_page } = this.props.graph
+ const page = pages[page_path] || pages[home_page]
+ if (!this.props.interactive && hasAutoplay(page)) {
+ this.setState({ page, popups: {}, hidden: {}, roadblock: true })
+ } else {
+ this.setState({ page, popups: {}, hidden: {}, roadblock: false })
+ actions.site.interact()
+ this.props.audio.player.playPage(page)
+ this.resetTimer(page)
+ }
+ }
+
+ resetTimer(page) {
+ clearTimeout(this.timeout)
+ const maxDeferTime = page.tiles.reduce((max_time, tile) => Math.max(tile.settings.appear_after || 0, max_time), 0)
+ if (maxDeferTime) {
+ this.setState({ time: 0, maxDeferTime })
+ this.timeout = setTimeout(this.updateTimer, 500)
+ }
+ }
+
+ updateTimer() {
+ clearTimeout(this.timeout)
+ this.setState({ time: this.state.time + 0.500 })
+ if (this.state.time < this.state.maxDeferTime) {
+ this.timeout = setTimeout(this.updateTimer, 500)
+ }
+ }
+
+ handleResize() {
+ this.setState({
+ bounds: {
+ width: window.innerWidth,
+ height: window.innerHeight,
+ }
+ })
+ }
+
+ handleMouseDown(e, tile) {
+ if (tile.href) {
+ if (tile.href.indexOf('http') === 0) {
+ window.location.href = tile.href
+ return
+ }
+ else if (tile.href === '__open_popup') {
+ this.setState({
+ popups: {
+ ...this.state.popups,
+ [tile.settings.target_popup]: true,
+ },
+ })
+ }
+ else if (tile.href === '__close_popup') {
+ this.setState({
+ popups: {
+ ...this.state.popups,
+ [tile.settings.target_popup]: false,
+ },
+ })
+ }
+ else if (!tile.settings.navigate_when_audio_finishes) {
+ history.push(tile.href)
+ }
+ }
+ if (tile.settings.audio_on_click_id > 0) {
+ this.props.audio.player.playTile({
+ type: "click",
+ tile,
+ })
+ }
+ if (tile.settings.hide_on_click) {
+ this.setState({
+ hidden: {
+ ...this.state.hidden,
+ [tile.id]: true,
+ }
+ })
+ }
+ }
+
+ handlePlaybackEnded(tile) {
+ if (tile.href && tile.settings.autoadvance) {
+ history.push(tile.href)
+ }
+ }
+
+ render() {
+ const { page, audio, popups, hidden, time } = this.state
+ if (this.state.roadblock) {
+ return this.renderRoadblock()
+ }
+ if (this.props.graph.loading || !page.id) {
+ return (
+ <div>
+ <div className='body'>
+ <div className='page loading'>
+ <Loader />
+ </div>
+ </div>
+ </div>
+ )
+ }
+ const { settings } = page
+ const pageStyle = { backgroundColor: settings ? settings.background_color : '#000000' }
+ const videoBounds = (page.tiles.length && page.tiles[0].type === 'video') ? {
+ width: page.tiles[0].settings.width,
+ height: page.tiles[0].settings.height,
+ } : this.state.bounds
+ // console.log(page)
+ return (
+ <div className='body'>
+ <div className='page' ref={this.pageRef} style={pageStyle}>
+ {page.tiles.map(tile => {
+ if (tile.settings.is_popup && !popups[tile.settings.popup_group]) return
+ if (tile.settings.appear_after && time < tile.settings.appear_after) return
+ if (tile.settings.hide_on_click && hidden[tile.id]) return
+ return (
+ <TileHandle
+ viewing
+ key={tile.id}
+ tile={tile}
+ audio={audio}
+ bounds={this.state.bounds}
+ videoBounds={videoBounds}
+ onMouseDown={e => this.handleMouseDown(e, tile)}
+ onPlaybackEnded={e => this.handlePlaybackEnded(e, tile)}
+ onDoubleClick={e => {}}
+ />
+ )
+ })}
+ </div>
+ </div>
+ )
+ }
+
+ removeRoadblock() {
+ console.log("remove roadblock")
+ actions.site.interact()
+ this.setState({ roadblock: false })
+ this.props.audio.player.playPage(this.state.page)
+ this.resetTimer(this.state.page)
+ }
+
+ renderRoadblock() {
+ const { title } = this.props.graph
+ return (
+ <div className='roadblock' onClick={this.removeRoadblock}>
+ <div>
+ <h2>{title}</h2>
+ <button>Enter</button>
+ </div>
+ </div>
+ )
+ }
+}
+
+const hasAutoplay = page => {
+ const hasAutoplayVideo = page.tiles.some(tile => {
+ return tile.type === 'video' && !tile.settings.muted
+ })
+ const hasAutoplayAudio = page.settings.background_audio_id > 0
+ return hasAutoplayAudio || hasAutoplayVideo
+}
+
+const mapStateToProps = state => ({
+ site: state.site,
+ audio: state.audio,
+ graph: state.site.graph,
+ interactive: state.site.interactive,
+})
+
+const mapDispatchToProps = dispatch => ({
+})
+
+export default connect(mapStateToProps, mapDispatchToProps)(ViewerContainer)