Skip to content

useMediaPlayer Hook

Metadata

  • System type: library

System Intent

  • What this is: A shared React hook (main/app/lib/hooks/useMediaPlayer.ts) that centralises playback state management — play/pause, position, duration, mute, and controls-overlay visibility — for both AudioPlayer and VideoPlayer components. It provides stable callbacks for toggling play, mute, scrubbing, and handling tap-to-toggle controls, plus a showControlsBriefly helper that auto-hides the overlay after 3 s. An optional onStateChange callback fires whenever any state value changes.

Mermaid Diagram

flowchart TD
  Caller[AudioPlayer / VideoPlayer] -->|useMediaPlayer options| Hook[useMediaPlayer]
  Hook -->|returns state| Caller
  Caller -->|togglePlay| Hook
  Hook -->|setIsPlaying toggle| State[isPlaying / position / duration / isMuted / controlsVisible]
  Caller -->|handleMediaTap| Hook
  Hook -->|setControlsVisible + setTimeout 3s| AutoHide[controlsVisible = false]
  Caller -->|toggleMute| Hook
  Hook -->|setIsMuted toggle| State
  Caller -->|handleScrub ratio| Hook
  Hook -->|setPosition ratio*duration| State

Flows

Flow: mediaPlayerState

  • Core files: main/app/lib/hooks/useMediaPlayer.ts
  • Test files: none currently

Types

MediaPlayerState {
  isPlaying: boolean
  position: number          (seconds)
  duration: number          (seconds)
  isMuted: boolean
  controlsVisible: boolean
}

UseMediaPlayerOptions {
  duration?: number         (initial duration, default 30)
  onStateChange?: (state: MediaPlayerState) => void
}

// Return value includes all MediaPlayerState fields plus:
setIsPlaying: (v: boolean) => void
setPosition: (v: number) => void
setDuration: (v: number) => void
setIsMuted: (v: boolean) => void
setControlsVisible: (v: boolean) => void
togglePlay: () => void
toggleMute: () => void
handleScrub: (ratio: number) => void   // ratio in [0, 1]; clamped internally
handleMediaTap: () => void
showControlsBriefly: () => void

Paths

path input output path-type notes
mediaPlayerState.togglePlay call togglePlay() isPlaying flipped; showControlsBriefly fired happy path
mediaPlayerState.toggleMute call toggleMute() isMuted flipped; showControlsBriefly fired happy path
mediaPlayerState.scrub handleScrub(ratio) position = clamp(ratio,0,1)*duration; showControlsBriefly happy path ratio clamped to [0,1]
mediaPlayerState.tapShow handleMediaTap() while hidden controlsVisible = true; auto-hide timer set (3 s) happy path
mediaPlayerState.tapHide handleMediaTap() while visible controlsVisible = false; existing timer cleared happy path
mediaPlayerState.showBriefly showControlsBriefly() controlsVisible = true; any prior timer cancelled; new 3 s timer set happy path
mediaPlayerState.stateChange any state change onStateChange called with current snapshot happy path only fires if onStateChange provided
mediaPlayerState.unmount component unmounts pending auto-hide timer cleared happy path prevents setState on unmounted component

Pseudocode

showControlsBriefly():
  setControlsVisible(true)
  clearTimeout(controlsTimerRef)
  controlsTimerRef = setTimeout(() => setControlsVisible(false), 3000)

handleMediaTap():
  setControlsVisible(prev =>
    if prev:   // hiding
      clearTimeout(controlsTimerRef); return false
    else:      // showing
      clearTimeout + set new 3s timer; return true
  )

handleScrub(ratio):
  seconds = clamp(ratio, 0, 1) * duration
  setPosition(seconds)
  showControlsBriefly()

useEffect cleanup:
  clearTimeout(controlsTimerRef)

Logs

Source Location
React Native Metro / device console

Deployment

  • Mechanism: local only
  • Deploy command:
    cd main/app && npx expo start
    
  • Notes: Pure React hook — no native dependencies. Consumed by AudioPlayer and VideoPlayer (inside MemoryViewerModal).