diff --git a/frontend/app/components/Session/WebPlayer.tsx b/frontend/app/components/Session/WebPlayer.tsx index 811d6b9ba..c3565321a 100644 --- a/frontend/app/components/Session/WebPlayer.tsx +++ b/frontend/app/components/Session/WebPlayer.tsx @@ -7,7 +7,8 @@ import { PlayerProvider, createWebPlayer, } from 'Player'; - +import { makeAutoObservable } from 'mobx' +import { observer } from "mobx-react-lite" import withLocationHandlers from 'HOCs/withLocationHandlers'; import { useStore } from 'App/mstore'; import PlayerBlockHeader from '../Session_/PlayerBlockHeader'; @@ -35,7 +36,10 @@ function WebPlayer(props: any) { useEffect(() => { fetchList('issues'); - const [WebPlayerInst, PlayerStore] = createWebPlayer(session, jwt); + const [WebPlayerInst, PlayerStore] = createWebPlayer( + session, + (state) => makeAutoObservable(state) + ); setContextValue({ player: WebPlayerInst, store: PlayerStore }) // initPlayer(session, jwt); TODOPlayer diff --git a/frontend/app/components/Session_/Player/Controls/Timeline.js b/frontend/app/components/Session_/Player/Controls/Timeline.js index e3ce9788a..9a4d0595b 100644 --- a/frontend/app/components/Session_/Player/Controls/Timeline.js +++ b/frontend/app/components/Session_/Player/Controls/Timeline.js @@ -1,7 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; import { Icon } from 'UI' -import { connectPlayer, Controls, toggleTimetravel } from 'Player'; import TimeTracker from './TimeTracker'; import stl from './timeline.module.css'; import { setTimelinePointer, setTimelineHoverTime } from 'Duck/sessions'; @@ -9,6 +8,8 @@ import DraggableCircle from './DraggableCircle'; import CustomDragLayer from './CustomDragLayer'; import { debounce } from 'App/utils'; import TooltipContainer from './components/TooltipContainer'; +import { PlayerContext } from 'App/components/Session/playerContext'; +import { observer } from 'mobx-react-lite'; const BOUNDRY = 0; @@ -20,105 +21,63 @@ function getTimelinePosition(value, scale) { let deboucneJump = () => null; let debounceTooltipChange = () => null; -@connectPlayer((state) => ({ - playing: state.playing, - time: state.time, - skipIntervals: state.skipIntervals, - events: state.eventList, - skip: state.skip, - skipToIssue: state.skipToIssue, - disabled: state.cssLoading || state.messagesLoading || state.markedTargets, - endTime: state.endTime, - live: state.live, - notes: state.notes || [], // TODO: implement notes without interaction with Player state -})) -@connect( - (state) => ({ - issues: state.getIn(['sessions', 'current', 'issues']), - startedAt: state.getIn(['sessions', 'current', 'startedAt']), - tooltipVisible: state.getIn(['sessions', 'timeLineTooltip', 'isVisible']), - }), - { setTimelinePointer, setTimelineHoverTime } -) -export default class Timeline extends React.PureComponent { - progressRef = React.createRef(); - timelineRef = React.createRef(); - wasPlaying = false; - seekProgress = (e) => { - const time = this.getTime(e); - this.props.jump(time); - this.hideTimeTooltip(); - }; - loadAndSeek = async (e) => { - e.persist(); - await toggleTimetravel(); +function Timeline(props) { + const { player, store } = React.useContext(PlayerContext) + const [wasPlaying, setWasPlaying] = React.useState(false); + const { + playing, + time, + skipIntervals, + eventList: events, + skip, + skipToIssue, + disabled, + endTime, + live, + notes = [], + } = store.get() - setTimeout(() => { - this.seekProgress(e); - }); - }; + const progressRef = React.useRef(); + const timelineRef = React.useRef(); - jumpToTime = (e) => { - if (this.props.live && !this.props.liveTimeTravel) { - this.loadAndSeek(e); - } else { - this.seekProgress(e); - } - }; - getTime = (e, customEndTime) => { - const { endTime } = this.props; - const p = e.nativeEvent.offsetX / e.target.offsetWidth; - const targetTime = customEndTime || endTime; - const time = Math.max(Math.round(p * targetTime), 0); + const scale = 100 / endTime; - return time; - }; - - createEventClickHandler = (pointer) => (e) => { - e.stopPropagation(); - this.props.jump(pointer.time); - this.props.setTimelinePointer(pointer); - }; - - componentDidMount() { - const { issues, skipToIssue } = this.props; + React.useEffect(() => { + const { issues } = props; const firstIssue = issues.get(0); - deboucneJump = debounce(this.props.jump, 500); - debounceTooltipChange = debounce(this.props.setTimelineHoverTime, 50); + deboucneJump = debounce(player.jump, 500); + debounceTooltipChange = debounce(props.setTimelineHoverTime, 50); if (firstIssue && skipToIssue) { - this.props.jump(firstIssue.time); + player.jump(firstIssue.time); } - } + }, []) - onDragEnd = () => { - const { live, liveTimeTravel } = this.props; + const onDragEnd = () => { if (live && !liveTimeTravel) return; - if (this.wasPlaying) { - this.props.togglePlay(); + if (wasPlaying) { + player.togglePlay(); } }; - onDrag = (offset) => { - const { endTime, live, liveTimeTravel } = this.props; + const onDrag = (offset) => { if (live && !liveTimeTravel) return; - const p = (offset.x - BOUNDRY) / this.progressRef.current.offsetWidth; + const p = (offset.x - BOUNDRY) / progressRef.current.offsetWidth; const time = Math.max(Math.round(p * endTime), 0); deboucneJump(time); - this.hideTimeTooltip(); - if (this.props.playing) { - this.wasPlaying = true; - this.props.pause(); + hideTimeTooltip(); + if (playing) { + setWasPlaying(true) + player.pause(); } }; - getLiveTime = (e) => { - const { startedAt } = this.props; + const getLiveTime = (e) => { const duration = new Date().getTime() - startedAt; const p = e.nativeEvent.offsetX / e.target.offsetWidth; const time = Math.max(Math.round(p * duration), 0); @@ -126,23 +85,23 @@ export default class Timeline extends React.PureComponent { return [time, duration]; }; - showTimeTooltip = (e) => { - if (e.target !== this.progressRef.current && e.target !== this.timelineRef.current) { - return this.props.tooltipVisible && this.hideTimeTooltip(); + const showTimeTooltip = (e) => { + if (e.target !== progressRef.current && e.target !== timelineRef.current) { + return props.tooltipVisible && hideTimeTooltip(); } - const { live } = this.props; + let timeLineTooltip; if (live) { - const [time, duration] = this.getLiveTime(e); + const [time, duration] = getLiveTime(e); timeLineTooltip = { time: duration - time, offset: e.nativeEvent.offsetX, isVisible: true, }; } else { - const time = this.getTime(e); + const time = getTime(e); timeLineTooltip = { time: time, offset: e.nativeEvent.offsetX, @@ -153,18 +112,44 @@ export default class Timeline extends React.PureComponent { debounceTooltipChange(timeLineTooltip); }; - hideTimeTooltip = () => { + const hideTimeTooltip = () => { const timeLineTooltip = { isVisible: false }; debounceTooltipChange(timeLineTooltip); }; - render() { - const { events, skip, skipIntervals, disabled, endTime, live, notes } = this.props; + const seekProgress = (e) => { + const time = getTime(e); + player.jump(time); + hideTimeTooltip(); + }; - const scale = 100 / endTime; + const loadAndSeek = async (e) => { + e.persist(); + await toggleTimetravel(); - return ( -
{ + seekProgress(e); + }); + }; + + const jumpToTime = (e) => { + if (live && !liveTimeTravel) { + loadAndSeek(e); + } else { + seekProgress(e); + } + }; + + const getTime = (e, customEndTime) => { + const p = e.nativeEvent.offsetX / e.target.offsetWidth; + const targetTime = customEndTime || endTime; + const time = Math.max(Math.round(p * targetTime), 0); + + return time; + }; + + return ( +
{/* custo color is live */} - + {!live && skip ? skipIntervals.map((interval) => ( @@ -208,7 +193,7 @@ export default class Timeline extends React.PureComponent { }} /> )) : null} -
+
{events.map((e) => (
- ); - } + ) } + +export default connect( + (state) => ({ + issues: state.getIn(['sessions', 'current', 'issues']), + startedAt: state.getIn(['sessions', 'current', 'startedAt']), + tooltipVisible: state.getIn(['sessions', 'timeLineTooltip', 'isVisible']), + }), + { setTimelinePointer, setTimelineHoverTime } +)(observer(Timeline)) diff --git a/frontend/app/components/Session_/Player/Overlay.tsx b/frontend/app/components/Session_/Player/Overlay.tsx index 7b610ded1..d9a73c56a 100644 --- a/frontend/app/components/Session_/Player/Overlay.tsx +++ b/frontend/app/components/Session_/Player/Overlay.tsx @@ -1,7 +1,5 @@ import React from 'react'; -import { connectPlayer } from 'Player'; import { getStatusText } from 'Player'; -import type { MarkedTarget } from 'Player'; import { CallingState, ConnectionStatus, RemoteControlStatus } from 'Player'; import AutoplayTimer from './Overlay/AutoplayTimer'; @@ -10,45 +8,39 @@ import LiveStatusText from './Overlay/LiveStatusText'; import Loader from './Overlay/Loader'; import ElementsMarker from './Overlay/ElementsMarker'; import RequestingWindow, { WindowType } from 'App/components/Assist/RequestingWindow'; +import { PlayerContext } from 'App/components/Session/playerContext'; +import { observer } from 'mobx-react-lite'; interface Props { - playing: boolean, - completed: boolean, - inspectorMode: boolean, - loading: boolean, - live: boolean, - liveStatusText: string, - concetionStatus: ConnectionStatus, - autoplay: boolean, - markedTargets: MarkedTarget[] | null, - activeTargetIndex: number, - calling: CallingState, - remoteControl: RemoteControlStatus - nextId: string, - togglePlay: () => void, closedLive?: boolean, - livePlay?: boolean, } function Overlay({ - playing, - completed, - inspectorMode, - loading, - live, - liveStatusText, - concetionStatus, - autoplay, - markedTargets, - activeTargetIndex, nextId, - togglePlay, closedLive, - livePlay, - calling, - remoteControl, }: Props) { + const { player, store } = React.useContext(PlayerContext) + + const { + playing, + messagesLoading, + cssLoading, + completed, + autoplay, + inspectorMode, + live, + peerConnectionStatus, + markedTargets, + activeTargetIndex, + livePlay, + calling, + remoteControl, + } = store.get() + const loading = messagesLoading || cssLoading + const liveStatusText = getStatusText(peerConnectionStatus) + const concetionStatus = peerConnectionStatus + const showAutoplayTimer = !live && completed && autoplay && nextId const showPlayIconLayer = !live && !markedTargets && !inspectorMode && !loading && !showAutoplayTimer; const showLiveStatusText = live && livePlay && liveStatusText && !loading; @@ -65,7 +57,7 @@ function Overlay({ } { loading ? : null } { showPlayIconLayer && - + } { markedTargets && } @@ -74,18 +66,4 @@ function Overlay({ } -export default connectPlayer(state => ({ - playing: state.playing, - loading: state.messagesLoading || state.cssLoading, - completed: state.completed, - autoplay: state.autoplay, - inspectorMode: state.inspectorMode, - live: state.live, - liveStatusText: getStatusText(state.peerConnectionStatus), - concetionStatus: state.peerConnectionStatus, - markedTargets: state.markedTargets, - activeTargetIndex: state.activeTargetIndex, - livePlay: state.livePlay, - calling: state.calling, - remoteControl: state.remoteControl, -}))(Overlay); +export default observer(Overlay); diff --git a/frontend/app/components/Session_/Player/Player.js b/frontend/app/components/Session_/Player/Player.js index ea3640847..a37fca62b 100644 --- a/frontend/app/components/Session_/Player/Player.js +++ b/frontend/app/components/Session_/Player/Player.js @@ -73,7 +73,7 @@ function Player(props) { > {fullscreen && }
- +
{!fullscreen && !!bottomBlock && ( @@ -94,7 +94,11 @@ function Player(props) { {bottomBlock === INSPECTOR && }
)} - +
) }