package com.inprogress.reactnativeyoutube; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; import android.os.Handler; import com.google.android.youtube.player.YouTubeInitializationResult; import com.google.android.youtube.player.YouTubePlayer; import com.facebook.react.bridge.ReadableArray; import java.util.ArrayList; import java.util.List; import java.lang.Runnable; public class YouTubePlayerController implements YouTubePlayer.OnInitializedListener, YouTubePlayer.PlayerStateChangeListener, YouTubePlayer.PlaybackEventListener, YouTubePlayer.OnFullscreenListener { private YouTubePlayer mYouTubePlayer; private YouTubeView mYouTubeView; private static final int VIDEO_MODE = 0; private static final int VIDEOS_MODE = 1; private static final int PLAYLIST_MODE = 2; private boolean mIsLoaded = false; private boolean mIsReady = false; private int mMode = 0; private int mVideosIndex = 0; private String mVideoId = null; private List<String> mVideoIds = new ArrayList<String>(); private String mPlaylistId = null; private boolean mPlay = false; private boolean mLoop = false; private boolean mFullscreen = false; private int mControls = 1; private boolean mShowFullscreenButton = true; private boolean mResumePlay = true; public YouTubePlayerController(YouTubeView youTubeView) { mYouTubeView = youTubeView; } @Override public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean wasRestored) { if (!wasRestored) { mYouTubePlayer = youTubePlayer; mYouTubePlayer.setPlayerStateChangeListener(this); mYouTubePlayer.setPlaybackEventListener(this); mYouTubePlayer.setOnFullscreenListener(this); updateFullscreen(); updateShowFullscreenButton(); updateControls(); if (mVideoId != null) loadVideo(); else if (!mVideoIds.isEmpty()) loadVideos(); else if (mPlaylistId != null) loadPlaylist(); } } @Override public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult result) { if (result.isUserRecoverableError()) { result.getErrorDialog(mYouTubeView.getReactContext().getCurrentActivity(), 0).show(); } mYouTubeView.receivedError(result.toString()); } @Override public void onPlaying() { mYouTubeView.didChangeToState("playing"); } @Override public void onPaused() { mYouTubeView.didChangeToState("paused"); } @Override public void onStopped() { mYouTubeView.didChangeToState("stopped"); } @Override public void onBuffering(boolean buffering) { if (buffering) mYouTubeView.didChangeToState("buffering"); //Trick to remove when YouTube will patch it ProgressBar progressBar; try { // As of 2016-02-16, the ProgressBar is at position 0 -> 3 -> 2 in the view tree of the Youtube Player Fragment ViewGroup child1 = (ViewGroup) mYouTubeView.getChildAt(0); ViewGroup child2 = (ViewGroup) child1.getChildAt(3); progressBar = (ProgressBar) child2.getChildAt(2); } catch (Throwable t) { // As its position may change, we fallback to looking for it progressBar = findProgressBar(mYouTubeView); } int visibility = buffering ? View.VISIBLE : View.INVISIBLE; if (progressBar != null) progressBar.setVisibility(visibility); } @Override public void onSeekTo(int i) { mYouTubeView.didChangeToSeeking(i); } @Override public void onLoading() { mYouTubeView.didChangeToState("loading"); } @Override public void onLoaded(String videoId) { if (isVideosMode()) setVideosIndex(mVideoIds.indexOf(videoId)); if (!mIsReady) { mYouTubeView.playerViewDidBecomeReady(); setLoaded(true); mIsReady = true; } } @Override public void onAdStarted() { mYouTubeView.didChangeToState("adStarted"); } @Override public void onVideoStarted() { mYouTubeView.didChangeToState("started"); } @Override public void onVideoEnded() { mYouTubeView.didChangeToState("ended"); if (isLoop()) { if (isVideoMode()) loadVideo(); else if (isVideosMode() && getVideosIndex() == mVideoIds.size() - 1) playVideoAt(0); } } @Override public void onFullscreen(boolean isFullscreen) { mYouTubeView.didChangeToFullscreen(isFullscreen); } @Override public void onError(YouTubePlayer.ErrorReason errorReason) { mYouTubeView.receivedError(errorReason.toString()); } public void seekTo(int second) { if (isLoaded()) mYouTubePlayer.seekToMillis(second * 1000); } public int getCurrentTime() { return mYouTubePlayer.getCurrentTimeMillis() / 1000; } public int getDuration() { return mYouTubePlayer.getDurationMillis() / 1000; } public void nextVideo() { if (isLoaded()) { if (mYouTubePlayer.hasNext()) mYouTubePlayer.next(); else if (isLoop()) { if (isVideosMode()) playVideoAt(0); else if (isPlaylistMode()) loadPlaylist(); else loadVideo(); } } } public void previousVideo() { if (isLoaded()) { if (mYouTubePlayer.hasPrevious()) mYouTubePlayer.previous(); else if (isLoop()) { if (isVideosMode()) playVideoAt(mVideoIds.size() - 1); else if (isPlaylistMode()) loadPlaylist(); else loadVideo(); } } } public void playVideoAt(int index) { if (isLoaded() && isVideosMode()) { boolean indexIsInRange = setVideosIndex(index); if (indexIsInRange) loadVideos(); else mYouTubeView.receivedError("Video index is out of bound for videoIds[]"); } } /** * Private methods **/ private void loadVideo() { if (isPlay()) mYouTubePlayer.loadVideo(mVideoId); else mYouTubePlayer.cueVideo(mVideoId); setVideosIndex(0); setVideoMode(); } private void loadVideos() { if (isPlay()) mYouTubePlayer.loadVideos(mVideoIds, getVideosIndex(), 0); else mYouTubePlayer.cueVideos(mVideoIds, getVideosIndex(), 0); setVideosMode(); } private void loadPlaylist() { if (isPlay()) mYouTubePlayer.loadPlaylist(mPlaylistId); else mYouTubePlayer.cuePlaylist(mPlaylistId); setVideosIndex(0); setPlaylistMode(); } private void updateControls() { switch (mControls) { case 0: mYouTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.CHROMELESS); break; case 1: mYouTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.DEFAULT); break; case 2: mYouTubePlayer.setPlayerStyle(YouTubePlayer.PlayerStyle.MINIMAL); break; } } private void updateFullscreen() { mYouTubePlayer.setFullscreen(mFullscreen); } private void updateShowFullscreenButton() { mYouTubePlayer.setShowFullscreenButton(mShowFullscreenButton); } private ProgressBar findProgressBar(View view) { if (view instanceof ProgressBar) { return (ProgressBar) view; } else if (view instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view; for (int i = 0; i < viewGroup.getChildCount(); i++) { ProgressBar res = findProgressBar(viewGroup.getChildAt(i)); if (res != null) return res; } } return null; } /** * Getters & Setters **/ private void setLoaded(boolean loaded) { mIsLoaded = loaded; } private boolean isLoaded() { return mIsLoaded; } private void setVideoMode() { mMode = VIDEO_MODE; } private boolean isVideoMode() { return (mMode == VIDEO_MODE); } private void setVideosMode() { mMode = VIDEOS_MODE; } private boolean isVideosMode() { return (mMode == VIDEOS_MODE); } private void setPlaylistMode() { mMode = PLAYLIST_MODE; } private boolean isPlaylistMode() { return (mMode == PLAYLIST_MODE); } private boolean setVideosIndex(int index) { if (index >= 0 && index < mVideoIds.size()) { mVideosIndex = index; return true; } else return false; } public int getVideosIndex() { return mVideosIndex; } public void onVideoFragmentResume() { if (isResumePlay() && mYouTubePlayer != null) { // For some reason calling mYouTubePlayer.play() right away is ineffective final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { mYouTubePlayer.play(); } }, 1); } } private boolean isPlay() { return mPlay; } private boolean isLoop() { return mLoop; } private boolean isFullscreen() { return mFullscreen; } private int getControls() { return mControls; } private boolean isResumePlay() { return mResumePlay; } /** * React Props */ public void setVideoId(String videoId) { mVideoId = videoId; if (isLoaded()) loadVideo(); } public void setVideoIds(ReadableArray videoIds) { if (videoIds != null) { setVideosIndex(0); mVideoIds.clear(); for (int i = 0; i < videoIds.size(); i++) { mVideoIds.add(videoIds.getString(i)); } if (isLoaded()) loadVideos(); } } public void setPlaylistId(String playlistId) { mPlaylistId = playlistId; if (isLoaded()) loadPlaylist(); } public void setPlay(boolean play) { mPlay = play; if (isLoaded()) { if (isPlay()) mYouTubePlayer.play(); else mYouTubePlayer.pause(); } } public void setLoop(boolean loop) { mLoop = loop; } public void setFullscreen(boolean fullscreen) { mFullscreen = fullscreen; if (isLoaded()) updateFullscreen(); } public void setControls(int controls) { if (controls >= 0 && controls <= 2) { mControls = controls; if (isLoaded()) updateControls(); } } public void setShowFullscreenButton(boolean show) { mShowFullscreenButton = show; if (isLoaded()) updateShowFullscreenButton(); } public void setResumePlay(boolean resumePlay) { mResumePlay = resumePlay; } }