Skip to content

Commit

Permalink
feat: add page fullscreen,rate switch,custom definition and some ui r…
Browse files Browse the repository at this point in the history
…efactor
  • Loading branch information
zuoxiaofei authored and ambar committed Sep 2, 2021
1 parent 7da911f commit 3e07b12
Show file tree
Hide file tree
Showing 23 changed files with 451 additions and 71 deletions.
9 changes: 9 additions & 0 deletions example/src/MP4Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@ const App = () => {
return (
<PlayerContainer
{...props}
localeConfig={{
'zh-Hans': {
'quality-ld': '流畅 360P',
'quality-sd': '清晰 480P',
'quality-hd': '高清 720P',
'quality-fhd': '超清 1080P',
},
}}
locale={'ja'}
dispatchRef={dispatchRef}
onEvent={(e, data) => {
if (shouldLoop && e === EVENTS.DOM.ENDED) {
Expand Down
11 changes: 8 additions & 3 deletions packages/griffith-message/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ declare const EVENTS: {
}

PLAYER: {
QUALITY_CHANGE: string
QUALITY_CHANGE: string,
CHANGE_QUALITY_START: string,
CHANGE_QUALITY_SUCCESS:string,
CHANGE_QUALITY_FAIL: string,
PLAYBACK_RATE_CHANGE: string
REQUEST_PLAY: string
REQUEST_PAUSE: string
PLAY_COUNT: string
Expand All @@ -37,8 +41,9 @@ declare const EVENTS: {
SHOW_CONTROLLER: string
HIDE_CONTROLLER: string
HOVER_PROGRESS_DOT: string
LEAVE_PROGRESS_DOT: string
SUBSCRIPTION_READY: string
LEAVE_PROGRESS_DOT: string,
ENTER_PAGE_FULLSCREEN: string,
EXIT_PAGE_FULLSCREEN: string
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/griffith-message/src/constants/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const PLAYER = {
SET_VOLUME: 'action/player/set-volume',
ENTER_FULLSCREEN: 'action/player/enter-fullscreen',
EXIT_FULLSCREEN: 'action/player/exit-fullscreen',
ENTER_PAGE_FULLSCREEN: 'event/player/enter-page-fullscreen',
EXIT_PAGE_FULLSCREEN: 'event/player/exit-page-fullscreen',
ENTER_PIP: 'action/player/enter-pip',
EXIT_PIP: 'action/player/exit-pip',
TIME_UPDATE: 'action/player/time-update',
Expand Down
6 changes: 6 additions & 0 deletions packages/griffith-message/src/constants/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ export const DOM = {
// custom events
export const PLAYER = {
QUALITY_CHANGE: 'event/player/quality-change',
CHANGE_QUALITY_START: 'event/player/quality-change-start',
CHANGE_QUALITY_SUCCESS: 'event/player/quality-change-success',
CHANGE_QUALITY_FAIL: 'event/player/quality-change-fail',
PLAYBACK_RATE_CHANGE: 'event/player/rate-change',
REQUEST_PLAY: 'event/player/request-play',
PLAY_REJECTED: 'event/player/play-rejected',
REQUEST_PAUSE: 'event/player/request-pause',
PLAY_COUNT: 'event/player/play-count',
PLAY_FAILED: 'event/player/play-failed',
ENTER_FULLSCREEN: 'event/player/enter-fullscreen',
EXIT_FULLSCREEN: 'event/player/exit-fullscreen',
ENTER_PAGE_FULLSCREEN: 'event/player/enter-page-fullscreen',
EXIT_PAGE_FULLSCREEN: 'event/player/exit-page-fullscreen',
ENTER_PIP: 'event/player/enter-pip',
EXIT_PIP: 'event/player/exit-pip',
SHOW_CONTROLLER: 'event/player/show-controller',
Expand Down
17 changes: 13 additions & 4 deletions packages/griffith/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import React from 'react'
import {EVENTS, ACTIONS} from 'griffith-message'

type RealQuality = 'ld' | 'sd' | 'hd' | 'fhd'

type Lans = 'en' | 'ja' | 'zh-Hans' | 'zh-Hant'
type LocaleKey = 'quality-auto' | 'quality-ld' | 'quality-sd' | 'quality-hd' | 'quality-fhd'
type LocaleObject =Partial<Record<LocaleKey,string>>
type LocaleConfig=Partial<Record<Lans,LocaleObject>>
interface IPlaybackRate{
value: number,
text: string
}
interface PlaySource {
bitrate?: number
duration?: number
Expand Down Expand Up @@ -32,7 +39,11 @@ interface PlayerContainerProps {
initialObjectFit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
useMSE?: boolean
locale?: 'en' | 'ja' | 'zh-Hans' | 'zh-Hant'
localeConfig?: LocaleConfig
defaultQuality?: RealQuality[]
defaultPlaybackRate?: IPlaybackRate
playbackRates?:Array<IPlaybackRate>
hiddenPlaybackRateItem?: boolean
}

interface Subscription {
Expand Down Expand Up @@ -68,13 +79,11 @@ interface VideoSourceContextValue {
currentQuality: Quality
currentSrc: string
setCurrentQuality: (q: Quality) => void
setCurrentPlaybackRate: (q: IPlaybackRate) => void
}

declare const PlayerContainer: React.ComponentType<PlayerContainerProps>
declare const MessageContext: React.Context<MessageContextValue>
declare const VideoSourceContext: React.Context<VideoSourceContextValue>
declare const Layer: React.ComponentType

export default PlayerContainer

export {VideoSourceContext, MessageContext, Layer, EVENTS, ACTIONS}
91 changes: 56 additions & 35 deletions packages/griffith/src/components/Controller/Controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import CombinedTimeItem from './items/CombinedTimeItem'
import QualityMenuItem from './items/QualityMenuItem'
import VolumeItem from './items/VolumeItem'
import FullScreenButtonItem from './items/FullScreenButtonItem'
import PageFullScreenButtonItem from './items/PageFullScreenButtonItem'
import PipButtonItem from './items/PipButtonItem'

import styles from './styles'
import PlaybackRateMenuItem from './items/PlaybackRateMenuItem'

class Controller extends Component {
static propTypes = {
Expand Down Expand Up @@ -47,6 +48,7 @@ class Controller extends Component {
hiddenQualityMenu: PropTypes.bool,
hiddenVolumeItem: PropTypes.bool,
hiddenFullScreenButton: PropTypes.bool,
hiddenPlaybackRateItem: PropTypes.bool,
}

static defaultProps = {
Expand All @@ -62,6 +64,7 @@ class Controller extends Component {
hiddenTimeline: false,
hiddenTime: false,
hiddenQualityMenu: false,
hiddenPlaybackRateItem: false,
hiddenVolumeItem: false,
hiddenFullScreenButton: false,
progressDots: [],
Expand Down Expand Up @@ -276,10 +279,12 @@ class Controller extends Component {
currentTime,
volume,
isFullScreen,
isPageFullScreen,
isPip,
onDragStart,
onDragEnd,
onToggleFullScreen,
onTogglePageFullScreen,
onTogglePip,
showPip,
progressDots,
Expand All @@ -288,6 +293,7 @@ class Controller extends Component {
hiddenTime,
hiddenQualityMenu,
hiddenVolumeItem,
hiddenPlaybackRateItem,
hiddenFullScreenButton,
onProgressDotHover,
onProgressDotLeave,
Expand All @@ -303,12 +309,6 @@ class Controller extends Component {

return (
<div className={css(styles.root, isFullScreen && styles.fullScreened)}>
{!hiddenPlayButton && (
<PlayButtonItem
isPlaying={isPlaying}
onClick={() => this.handleToggle('button')}
/>
)}
{!hiddenTimeline && (
<TimelineItem
value={currentTime}
Expand All @@ -323,34 +323,55 @@ class Controller extends Component {
onProgressDotLeave={onProgressDotLeave}
/>
)}
{hiddenTimeline && <div className={css(styles.timelineHolder)} />}
{!hiddenTime && (
<CombinedTimeItem
isFullScreen={isFullScreen}
currentTime={displayedCurrentTime}
duration={duration}
/>
)}
{!hiddenQualityMenu && <QualityMenuItem />}
{showPip && <PipButtonItem isPip={isPip} onClick={onTogglePip} />}
{!hiddenFullScreenButton && (
<FullScreenButtonItem
isFullScreen={isFullScreen}
onClick={onToggleFullScreen}
/>
)}
{!hiddenVolumeItem && (
<VolumeItem
volume={volume}
menuShown={isVolumeHovered || isVolumeDragging || isVolumeKeyboard}
onMouseEnter={this.handleVolumePointerEnter}
onMouseLeave={this.handleVolumePointerLeave}
onToggleMuted={this.handleToggleMuted}
onDragStart={this.handleVolumeDragStart}
onDragEnd={this.handleVolumeDragEnd}
onChange={this.handleVolumeChange}
/>
)}
<div className={css(styles.rootBottom)}>
<div className={css(styles.rootBottomLeft)}>
{!hiddenPlayButton && (
<PlayButtonItem
isPlaying={isPlaying}
onClick={() => this.handleToggle('button')}
/>
)}
{hiddenTimeline && <div className={css(styles.timelineHolder)} />}
{!hiddenTime && (
<CombinedTimeItem
isFullScreen={isFullScreen}
currentTime={displayedCurrentTime}
duration={duration}
/>
)}
</div>
<div className={css(styles.rootBottomRight)}>
{!hiddenPlaybackRateItem && <PlaybackRateMenuItem />}
{!hiddenQualityMenu && <QualityMenuItem />}
{showPip && <PipButtonItem isPip={isPip} onClick={onTogglePip} />}
{!hiddenFullScreenButton && (
<PageFullScreenButtonItem
isFullScreen={isPageFullScreen}
onClick={onTogglePageFullScreen}
/>
)}
{!hiddenFullScreenButton && (
<FullScreenButtonItem
isFullScreen={isFullScreen}
onClick={onToggleFullScreen}
/>
)}
{!hiddenVolumeItem && (
<VolumeItem
volume={volume}
menuShown={
isVolumeHovered || isVolumeDragging || isVolumeKeyboard
}
onMouseEnter={this.handleVolumePointerEnter}
onMouseLeave={this.handleVolumePointerLeave}
onToggleMuted={this.handleToggleMuted}
onDragStart={this.handleVolumeDragStart}
onDragEnd={this.handleVolumeDragEnd}
onChange={this.handleVolumeChange}
/>
)}
</div>
</div>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react'
import {css} from 'aphrodite/no-important'
import {ua} from 'griffith-utils'
import styles from '../styles'
import Icon from '../../Icon'
import * as icons from '../../Icon/icons/controller'
import Tooltip from '../../Tooltip'
import Hover from '../../Hover'

const {isMobile} = ua

const PageFullScreenButtonItem = ({isFullScreen, onClick}) => (
<Hover className={css(styles.menuContainer)}>
{isFullScreenHovered => (
<React.Fragment>
<button className={css(styles.button)} onClick={onClick}>
<Icon
icon={isFullScreen ? icons.exitPageScreen : icons.enterPageScreen}
/>
</button>
<div
className={css(
styles.fullScreenTooltip,
styles.menu,
isFullScreenHovered && styles.menuShown,
isFullScreen && styles.fullScreenTooltipWide
)}
>
{!isMobile && (
<Tooltip
content={
isFullScreen
? 'action-exit-page-fullscreen'
: 'action-enter-page-fullscreen'
}
/>
)}
</div>
</React.Fragment>
)}
</Hover>
)

export default PageFullScreenButtonItem
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react'
import {css} from 'aphrodite/no-important'

import {VideoSourceContext} from '../../../contexts/VideoSource'
import reverseArray from '../../../utils/reverseArray'

import styles from '../styles'
import TranslatedText from '../../TranslatedText'

class PlaybackRateMenuItem extends React.PureComponent {
state = {
isPlaybackRateHovered: false,
}

handlePlaybackRatePointerEnter = () => {
this.setState({isPlaybackRateHovered: true})
}

handlePlaybackRatePointerLeave = () => {
this.setState({isPlaybackRateHovered: false})
}
handleClickItem = (q, handler) => {
this.handlePlaybackRatePointerLeave()
handler(q)
}

render() {
const {isPlaybackRateHovered} = this.state
return (
<VideoSourceContext.Consumer>
{({playbackRates, setCurrentPlaybackRate, currentPlaybackRate}) =>
playbackRates.length > 1 && (
<div
className={css(styles.menuContainer)}
onMouseEnter={this.handlePlaybackRatePointerEnter}
onMouseLeave={this.handlePlaybackRatePointerLeave}
>
<button className={css(styles.button, styles.qualityButton)}>
<span className={css(styles.qualityButtonText)}>
{currentPlaybackRate.value === 1.0 ? (
<TranslatedText name={'playback-rate'} />
) : (
`${currentPlaybackRate.text}`
)}
</span>
</button>
<div
className={css(
styles.menu,
isPlaybackRateHovered && styles.menuShown
)}
>
<div className={css(styles.qualityMenu)}>
{reverseArray(playbackRates).map(q => (
<button
key={q.value}
className={css(
styles.qualityMenuItem,
currentPlaybackRate.value === q.value &&
styles.qualityMenuActiveItem
)}
onClick={() => {
this.handleClickItem(q, setCurrentPlaybackRate)
}}
>
{q.text}
</button>
))}
</div>
</div>
</div>
)
}
</VideoSourceContext.Consumer>
)
}
}

export default PlaybackRateMenuItem
Loading

0 comments on commit 3e07b12

Please sign in to comment.