taro-material
Version:
Mini Program components that implement Google's Material Design.
439 lines (401 loc) • 11 kB
JavaScript
import Taro, { Component } from '@tarojs/taro';
import { View, LivePlayer, CoverView, CoverImage } from '@tarojs/components';
import PropTypes from 'prop-types';
import theme from '../styles/theme';
import './LivePlayer.scss';
import FullScreen from './images/fullscreen.png';
import Refresh from './images/refresh.png';
import FullScreenExit from './images/fullscreen_exit.png';
import ArrowUp from './images/arrow_drop_up.png';
import ArrowDown from './images/arrow_down.png';
import RoundPlayCircle from './images/round_play_circle.png';
import RoundPauseCircle from './images/round_pause_circle.png';
// const [
// FullScreen,
// Refresh,
// FullScreenExit,
// ArrowUp,
// ArrowDown,
// RoundPlayCircle,
// RoundPauseCircle,
// ] = [
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/fullscreen.png',
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/refresh.png',
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/fullscreen_exit.png',
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/arrow_drop_up.png',
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/arrow_down.png',
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/round_play_circle.png',
// 'https://raw.githubusercontent.com/6thquake/taro-material/master/packages/taro-material/src/LivePlayer/images/round_pause_circle.png',
// ];
class RMLivePlayer extends Component {
livePlayerContext = null;
constructor(props) {
super(props);
this.state = {
livePlayerId:
props.livePlayerId ||
`live-player-${new Date().getTime()}-${Math.floor(Math.random() * 100)}`,
isFullScreen: false,
show: true,
qshow: false,
src: props.src,
loading: false,
play: props.autoplay,
};
}
componentDidMount() {
const { livePlayerId } = this.state;
this.livePlayerContext = Taro.createLivePlayerContext(livePlayerId, this.$scope);
}
handleScreenChange = e => {
const { fullScreen } = e.detail;
this.props.onFullScreenChange({ fullScreen });
this.setState({
isFullScreen: fullScreen,
});
};
toggleScreen = isFullScreen => {
this.props.onFullScreenChange({ fullScreen: isFullScreen });
if (isFullScreen) {
this.exitFullScreen();
} else {
this.requestFullScreen();
}
};
requestFullScreen = () => {
this.livePlayerContext.requestFullScreen({
direction: -90,
success: res => {
this.setState({
isFullScreen: true,
});
},
fail: err => {
console.log('requestFullScreen err', err);
},
complete: res => {
console.log('finish', res);
},
});
};
exitFullScreen = () => {
this.livePlayerContext.exitFullScreen({
direction: 90,
success: res => {
console.log('exitFullScreen ok', res);
this.setState({
isFullScreen: false,
});
},
fail: err => {
console.log('exitFullScreen err', err);
},
complete: res => {
console.log('finish', res);
},
});
};
handleRefresh = () => {
const { src } = this.state;
this.setState({
src,
});
};
handlePlayerClick = () => {
this.setState({
show: !this.state.show,
qshow: false,
});
};
handleStateChange = e => {
this.props.onStateChange(e);
const { code, message } = e.detail;
const startCodes = [2002, 2007, 2008];
const endCodes = [2003, 2004];
if (startCodes.includes(code)) {
this.setState({
loading: true,
});
}
if (endCodes.includes(code)) {
this.setState({
loading: false,
});
}
};
handleNetStatus = e => {
this.props.onNetStatus(e);
};
handleError = e => {
this.props.onError(e);
};
handleQulityClick = e => {
this.setState(
{
qshow: !this.state.qshow,
},
() => {
// this.livePlayerContext.play()
},
);
};
handleControlsClick = e => {
e.stopPropagation();
};
handleListClick = (src, e) => {
e.stopPropagation();
this.setState({
qshow: false,
src,
});
};
handlePlay = () => {
this.setState(
{
play: true,
},
() => {
this.livePlayerContext.play();
this.props.onPlay();
},
);
};
handlePause = () => {
this.setState(
{
play: false,
},
() => {
this.livePlayerContext.pause();
this.props.onPause();
},
);
};
togglePlay = () => {
const { play } = this.state;
if (play) {
this.handlePause();
} else {
this.handlePlay();
}
};
render() {
const { play, livePlayerId, isFullScreen, show, qshow, src, loading } = this.state;
const {
mode,
autoplay,
muted,
orientation,
objectFit,
minCache,
maxCache,
title,
sources,
refreshable,
hasPlayBar,
customStyle,
} = this.props;
const qualityItem = sources.filter(item => item.src === src)[0];
const qualityName = qualityItem && qualityItem.name;
return (
<LivePlayer
onFullScreenChange={this.handleScreenChange}
onNetStatus={this.handleNetStatus}
onStateChange={this.handleStateChange}
autoplay={autoplay}
src={src}
mode={mode}
muted={muted}
orientation={orientation}
objectFit={objectFit}
minCache={minCache}
maxCache={maxCache}
id={livePlayerId}
className="player"
onError={theme.handleError}
style={customStyle}
>
<CoverView onClick={this.handlePlayerClick} className="box">
{!play && (
<CoverImage className="play-icon" onClick={this.handlePlay} src={RoundPlayCircle} />
)}
{loading && <CoverView className="loading">加载中...</CoverView>}
{show && (
<CoverView onClick={this.handleControlsClick} className="controls">
<CoverView className="left-box">
{hasPlayBar && (
<CoverImage
onClick={this.togglePlay}
className="image play-action"
src={play ? RoundPauseCircle : RoundPlayCircle}
/>
)}
<CoverView className="title">{title}</CoverView>
</CoverView>
<CoverView className="actions">
{refreshable && (
<CoverView className="refresh action">
<CoverImage className="image" onClick={this.handleRefresh} src={Refresh} />
</CoverView>
)}
{isFullScreen &&
qualityName && (
<CoverView onClick={this.handleQulityClick} className="action quality">
<CoverView className="name">{qualityName}</CoverView>
<CoverImage className="arrow" src={qshow ? ArrowDown : ArrowUp} />
</CoverView>
)}
<CoverView className="screen action">
<CoverImage
className="image"
onClick={this.toggleScreen.bind(this, isFullScreen)}
src={isFullScreen ? FullScreenExit : FullScreen}
/>
</CoverView>
</CoverView>
</CoverView>
)}
{qshow && (
<CoverView className="options">
{sources.map(item => (
<CoverView
onClick={theme.handleListClick.bind(this, item.src)}
className="option"
key={item.name}
>
{item.name}
</CoverView>
))}
</CoverView>
)}
</CoverView>
</LivePlayer>
);
}
}
RMLivePlayer.defaultProps = {
hasPlayBar: false,
refreshable: false,
/**
* 名称
*/
title: '',
livePlayerId: '',
/**
* 音视频地址。目前仅支持 flv, rtmp 格式
*/
src: '',
sources: [],
/**
* live(直播),RTC(实时通话,该模式时延更低)
*/
mode: 'live',
/**
* 自动播放
*/
autoplay: false,
/**
* 是否静音
*/
muted: false,
/**
* 画面方向,可选值有 vertical,horizontal
*/
orientation: 'vertical',
/**
* 填充模式,可选值有 contain,fillCrop
*/
objectFit: 'contain',
/**
* 最小缓冲区,单位s(RTC 模式推荐 0.2s)
*/
minCache: 1,
/**
* 最大缓冲区,单位s(RTC 模式推荐 0.8s)
*/
maxCache: 3,
/**
* 播放状态变化事件,detail = {code}
*/
onStateChange: () => {},
/**
* 全屏变化事件,detail = {direction, fullScreen}
*/
onFullScreenChange: () => {},
/**
* 网络状态通知,detail = {info}
*/
onNetStatus: () => {},
customStyle: {},
onError: () => {},
onPlay: () => {},
onPause: () => {},
};
RMLivePlayer.propTypes = {
/**
* 是否有暂停播放
*/
hasPlayBar: PropTypes.bool,
/**
* 是否可刷新
*/
refreshable: PropTypes.bool,
/**
* 名称
*/
title: PropTypes.string,
/**
* live-player的id
*/
livePlayerId: PropTypes.string,
/**
* 音视频地址。目前仅支持 flv, rtmp 格式
*/
src: PropTypes.string.isRequired,
sources: PropTypes.array,
/**
* live(直播),RTC(实时通话,该模式时延更低)
*/
mode: PropTypes.oneOf(['live', 'RTC']),
/**
* 自动播放
*/
autoplay: PropTypes.bool,
/**
* 是否静音
*/
muted: PropTypes.bool,
/**
* 画面方向,可选值有 vertical,horizontal
*/
orientation: PropTypes.oneOf(['vertical', 'horizontal']),
/**
* 填充模式,可选值有 contain,fillCrop
*/
objectFit: PropTypes.oneOf(['contain', 'fillCrop']),
/**
* 最小缓冲区,单位s(RTC 模式推荐 0.2s)
*/
minCache: PropTypes.number,
/**
* 最大缓冲区,单位s(RTC 模式推荐 0.8s)
*/
maxCache: PropTypes.number,
/**
* 播放状态变化事件,detail = {code}
*/
onStateChange: PropTypes.func,
/**
* 全屏变化事件,detail = {direction, fullScreen}
*/
onFullScreenChange: PropTypes.func,
/**
* 网络状态通知,detail = {info}
*/
onNetStatus: PropTypes.func,
customStyle: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
onError: PropTypes.func,
onPlay: PropTypes.func,
onPause: PropTypes.func,
};
export default RMLivePlayer;