import { useMemo } from 'react'; import { useAviationPlayer } from '../AviationContext'; import { devWarn } from '../logger'; import type { MediaSource } from '../imperative/MediaItem'; import type { AviationPlayer } from '../Aviation'; /** * Action methods for controlling media playback. * * This interface contains ONLY imperative action methods -- no reactive state. * Components that use only these actions will NOT re-render on playback state, * position, or current item changes. * * Every method routes through {@link AviationPlayer}; there is no second path * to the native engine here. */ export interface PlayerActions { /** * Start playback. * * - No arguments: resume current item. * - With a source argument: load it and start playing. */ play: (source?: MediaSource) => Promise; /** Pause playback. No-op if not playing. */ pause: () => Promise; /** Stop playback and release the current item. */ stop: () => Promise; /** * Seek to a position in milliseconds. * @param positionMs - Target position in milliseconds. */ seekTo: (positionMs: number) => Promise; /** * Skip to the next item in the queue. * Rejects if the queue is empty or at the end. */ skipToNext: () => Promise; /** * Skip to the previous item in the queue. * Rejects if there is no previous item. */ skipToPrevious: () => Promise; /** * Skip to a specific index in the queue. * @param index - Zero-based queue index. * @param autoPlay - Whether to start playing once loaded. Defaults to * `true`; pass `false` to position and load the item while leaving it * paused at its start. */ skipToIndex: (index: number, autoPlay?: boolean) => Promise; /** * Load a media item without starting playback. * * Accepts a bare URI string, a plain `MediaItemConfig`, or a pre-created * MediaItem instance; see {@link MediaSource} for how each form is * coerced. */ load: (source: MediaSource) => Promise; /** * Load a media item and begin playback. * * Use this when you already have a MediaItem instance (e.g. from * the queue). For simple URI playback, prefer {@link play} instead. */ loadAndPlay: (source: MediaSource) => Promise; } /** * React hook that returns ONLY imperative action methods for media playback. * * Unlike {@link usePlayer}, this hook does NOT subscribe to any reactive state. * Components using `usePlayerActions()` will NOT re-render when playback state, * media position, or the current item changes. This makes it ideal for: * * - Play/pause buttons that receive their visual state from a parent * - Skip controls * - Queue navigation triggers * - Any component that dispatches actions but doesn't display playback info * * The returned object has a stable identity (same reference across renders), * so it is safe to include in dependency arrays without causing re-renders. * * Reads the nearest provider player unless a player is passed explicitly. * * @example * ```tsx * function SkipButton() { * const { skipToNext } = usePlayerActions(); * return