package expo.modules.video.player import androidx.annotation.OptIn import androidx.media3.common.TrackSelectionParameters import androidx.media3.common.Tracks import androidx.media3.common.util.UnstableApi import expo.modules.video.enums.AudioMixingMode import expo.modules.video.enums.PlayerStatus import expo.modules.video.records.AudioTrack import expo.modules.video.records.AvailableSubtitleTracksChangedEventPayload import expo.modules.video.records.AvailableAudioTracksChangedEventPayload import expo.modules.video.records.IsPlayingEventPayload import expo.modules.video.records.MutedChangedEventPayload import expo.modules.video.records.PlaybackError import expo.modules.video.records.PlaybackRateChangedEventPayload import expo.modules.video.records.SourceChangedEventPayload import expo.modules.video.records.StatusChangedEventPayload import expo.modules.video.records.SubtitleTrack import expo.modules.video.records.SubtitleTrackChangedEventPayload import expo.modules.video.records.AudioTrackChangedEventPayload import expo.modules.video.records.TimeUpdate import expo.modules.video.records.VideoEventPayload import expo.modules.video.records.VideoSource import expo.modules.video.records.VideoSourceLoadedEventPayload import expo.modules.video.records.VideoTrack import expo.modules.video.records.VideoTrackChangedEventPayload import expo.modules.video.records.VolumeChangedEventPayload @OptIn(UnstableApi::class) sealed class PlayerEvent { open val name: String = "" open val jsEventPayload: VideoEventPayload? = null open val emitToJS: Boolean = true data class StatusChanged(val status: PlayerStatus, val oldStatus: PlayerStatus?, val error: PlaybackError?) : PlayerEvent() { override val name = "statusChange" override val jsEventPayload = StatusChangedEventPayload(status, oldStatus, error) } data class IsPlayingChanged(val isPlaying: Boolean, val oldIsPlaying: Boolean?) : PlayerEvent() { override val name = "playingChange" override val jsEventPayload = IsPlayingEventPayload(isPlaying, oldIsPlaying) } data class VolumeChanged(val volume: Float, val oldVolume: Float?) : PlayerEvent() { override val name = "volumeChange" override val jsEventPayload = VolumeChangedEventPayload(volume, oldVolume) } data class MutedChanged(val muted: Boolean, val oldMuted: Boolean?) : PlayerEvent() { override val name = "mutedChange" override val jsEventPayload = MutedChangedEventPayload(muted, oldMuted) } data class SourceChanged(val source: VideoSource?, val oldSource: VideoSource?) : PlayerEvent() { override val name = "sourceChange" override val jsEventPayload = SourceChangedEventPayload(source, oldSource) } data class PlaybackRateChanged(val rate: Float, val oldRate: Float?) : PlayerEvent() { override val name = "playbackRateChange" override val jsEventPayload = PlaybackRateChangedEventPayload(rate, oldRate) } data class TracksChanged(val tracks: Tracks) : PlayerEvent() { override val name = "tracksChange" override val emitToJS = false } data class TrackSelectionParametersChanged(val trackSelectionParameters: TrackSelectionParameters) : PlayerEvent() { override val name = "trackSelectionParametersChange" override val emitToJS = false } data class SubtitleTrackChanged(val subtitleTrack: SubtitleTrack?, val oldSubtitleTrack: SubtitleTrack?) : PlayerEvent() { override val name = "subtitleTrackChange" override val jsEventPayload = SubtitleTrackChangedEventPayload(subtitleTrack, oldSubtitleTrack) } data class AudioTrackChanged(val audioTrack: AudioTrack?, val oldAudioTrack: AudioTrack?) : PlayerEvent() { override val name = "audioTrackChange" override val jsEventPayload = AudioTrackChangedEventPayload(audioTrack, oldAudioTrack) } data class VideoTrackChanged(val videoTrack: VideoTrack?, val oldVideoTrack: VideoTrack?) : PlayerEvent() { override val name = "videoTrackChange" override val jsEventPayload = VideoTrackChangedEventPayload(videoTrack, oldVideoTrack) } class RenderedFirstFrame : PlayerEvent() { override val name = "renderFirstFrame" // This Event is emitted through the view (we are matching the AVKit API behavior) override val emitToJS = false } data class AvailableSubtitleTracksChanged( val availableSubtitleTracks: List, val oldAvailableSubtitleTracks: List ) : PlayerEvent() { override val name = "availableSubtitleTracksChange" override val jsEventPayload = AvailableSubtitleTracksChangedEventPayload(availableSubtitleTracks, oldAvailableSubtitleTracks) } data class AvailableAudioTracksChanged( val availableAudioTracks: List, val oldAvailableAudioTracks: List ) : PlayerEvent() { override val name = "availableAudioTracksChange" override val jsEventPayload = AvailableAudioTracksChangedEventPayload(availableAudioTracks, oldAvailableAudioTracks) } data class VideoSourceLoaded( val videoSource: VideoSource?, val duration: Double, val availableVideoTracks: List, val availableSubtitleTracks: List, val availableAudioTracks: List ) : PlayerEvent() { override val name = "sourceLoad" override val jsEventPayload = VideoSourceLoadedEventPayload( videoSource, duration, availableVideoTracks, availableSubtitleTracks, availableAudioTracks ) } data class TimeUpdated(val timeUpdate: TimeUpdate) : PlayerEvent() { override val name = "timeUpdate" override val jsEventPayload = timeUpdate } data class AudioMixingModeChanged(val audioMixingMode: AudioMixingMode, val oldAudioMixingMode: AudioMixingMode?) : PlayerEvent() { override val name = "audioMixingModeChange" override val emitToJS = false } class PlayedToEnd : PlayerEvent() { override val name = "playToEnd" } fun emit(player: VideoPlayer, listeners: List) { when (this) { is StatusChanged -> listeners.forEach { it.onStatusChanged(player, status, oldStatus, error) } is IsPlayingChanged -> listeners.forEach { it.onIsPlayingChanged(player, isPlaying, oldIsPlaying) } is VolumeChanged -> listeners.forEach { it.onVolumeChanged(player, volume, oldVolume) } is SourceChanged -> listeners.forEach { it.onSourceChanged(player, source, oldSource) } is PlaybackRateChanged -> listeners.forEach { it.onPlaybackRateChanged(player, rate, oldRate) } is TracksChanged -> listeners.forEach { it.onTracksChanged(player, tracks) } is TrackSelectionParametersChanged -> listeners.forEach { it.onTrackSelectionParametersChanged(player, trackSelectionParameters) } is TimeUpdated -> listeners.forEach { it.onTimeUpdate(player, timeUpdate) } is PlayedToEnd -> listeners.forEach { it.onPlayedToEnd(player) } is MutedChanged -> listeners.forEach { it.onMutedChanged(player, muted, oldMuted) } is AudioMixingModeChanged -> listeners.forEach { it.onAudioMixingModeChanged(player, audioMixingMode, oldAudioMixingMode) } is VideoTrackChanged -> listeners.forEach { it.onVideoTrackChanged(player, videoTrack, oldVideoTrack) } is RenderedFirstFrame -> listeners.forEach { it.onRenderedFirstFrame(player) } is VideoSourceLoaded -> listeners.forEach { it.onVideoSourceLoaded(player, videoSource, duration, availableVideoTracks, availableSubtitleTracks, availableAudioTracks) } // JS-only events - SubtitleTrackChanged - In the native events the TracksChanged can be used instead else -> Unit } } }