mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	Merge branch 'subtitles' of https://github.com/karyogamy/NewPipe into sub
This commit is contained in:
		| @@ -35,7 +35,9 @@ import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v7.widget.RecyclerView; | ||||
| import android.support.v7.widget.helper.ItemTouchHelper; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.util.Log; | ||||
| import android.util.TypedValue; | ||||
| import android.view.GestureDetector; | ||||
| import android.view.MotionEvent; | ||||
| import android.view.View; | ||||
| @@ -48,6 +50,8 @@ import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
|  | ||||
| import com.google.android.exoplayer2.Player; | ||||
| import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; | ||||
| import com.google.android.exoplayer2.ui.SubtitleView; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfo; | ||||
| @@ -61,7 +65,6 @@ import org.schabi.newpipe.util.AnimationUtils; | ||||
| import org.schabi.newpipe.util.ListHelper; | ||||
| import org.schabi.newpipe.util.NavigationHelper; | ||||
| import org.schabi.newpipe.util.PermissionHelper; | ||||
| import org.schabi.newpipe.util.PopupMenuIconHacker; | ||||
| import org.schabi.newpipe.util.ThemeHelper; | ||||
|  | ||||
| import java.util.List; | ||||
| @@ -194,7 +197,6 @@ public final class MainVideoPlayer extends Activity { | ||||
|         super.onConfigurationChanged(newConfig); | ||||
|  | ||||
|         if (playerImpl.isSomePopupMenuVisible()) { | ||||
|             playerImpl.moreOptionsPopupMenu.dismiss(); | ||||
|             playerImpl.getQualityPopupMenu().dismiss(); | ||||
|             playerImpl.getPlaybackSpeedPopupMenu().dismiss(); | ||||
|         } | ||||
| @@ -301,8 +303,11 @@ public final class MainVideoPlayer extends Activity { | ||||
|         private boolean queueVisible; | ||||
|  | ||||
|         private ImageButton moreOptionsButton; | ||||
|         public int moreOptionsPopupMenuGroupId = 89; | ||||
|         public PopupMenu moreOptionsPopupMenu; | ||||
|         private ImageButton toggleOrientationButton; | ||||
|         private ImageButton switchPopupButton; | ||||
|         private ImageButton switchBackgroundButton; | ||||
|  | ||||
|         private View secondaryControls; | ||||
|  | ||||
|         VideoPlayerImpl(final Context context) { | ||||
|             super("VideoPlayerImpl" + MainVideoPlayer.TAG, context); | ||||
| @@ -322,9 +327,12 @@ public final class MainVideoPlayer extends Activity { | ||||
|             this.playPauseButton = rootView.findViewById(R.id.playPauseButton); | ||||
|             this.playPreviousButton = rootView.findViewById(R.id.playPreviousButton); | ||||
|             this.playNextButton = rootView.findViewById(R.id.playNextButton); | ||||
|  | ||||
|             this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton); | ||||
|             this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton); | ||||
|             buildMoreOptionsMenu(); | ||||
|             this.secondaryControls = rootView.findViewById(R.id.secondaryControls); | ||||
|             this.toggleOrientationButton = rootView.findViewById(R.id.toggleOrientation); | ||||
|             this.switchBackgroundButton = rootView.findViewById(R.id.switchBackground); | ||||
|             this.switchPopupButton = rootView.findViewById(R.id.switchPopup); | ||||
|  | ||||
|             titleTextView.setSelected(true); | ||||
|             channelTextView.setSelected(true); | ||||
| @@ -332,6 +340,24 @@ public final class MainVideoPlayer extends Activity { | ||||
|             getRootView().setKeepScreenOn(true); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected void setupSubtitleView(@NonNull SubtitleView view, | ||||
|                                          @NonNull String captionSizeKey) { | ||||
|             final float captionRatioInverse; | ||||
|             if (captionSizeKey.equals(getString(R.string.smaller_caption_size_key))) { | ||||
|                 captionRatioInverse = 22f; | ||||
|             } else if (captionSizeKey.equals(getString(R.string.larger_caption_size_key))) { | ||||
|                 captionRatioInverse = 18f; | ||||
|             } else { | ||||
|                 captionRatioInverse = 20f; | ||||
|             } | ||||
|  | ||||
|             final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); | ||||
|             final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels); | ||||
|             view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX, | ||||
|                     (float) minimumLength / captionRatioInverse); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void initListeners() { | ||||
|             super.initListeners(); | ||||
| @@ -348,7 +374,11 @@ public final class MainVideoPlayer extends Activity { | ||||
|             playPauseButton.setOnClickListener(this); | ||||
|             playPreviousButton.setOnClickListener(this); | ||||
|             playNextButton.setOnClickListener(this); | ||||
|  | ||||
|             moreOptionsButton.setOnClickListener(this); | ||||
|             toggleOrientationButton.setOnClickListener(this); | ||||
|             switchBackgroundButton.setOnClickListener(this); | ||||
|             switchPopupButton.setOnClickListener(this); | ||||
|         } | ||||
|  | ||||
|         /*////////////////////////////////////////////////////////////////////////// | ||||
| @@ -464,6 +494,16 @@ public final class MainVideoPlayer extends Activity { | ||||
|                 return; | ||||
|             } else if (v.getId() == moreOptionsButton.getId()) { | ||||
|                 onMoreOptionsClicked(); | ||||
|  | ||||
|             } else if (v.getId() == toggleOrientationButton.getId()) { | ||||
|                 onScreenRotationClicked(); | ||||
|  | ||||
|             } else if (v.getId() == switchPopupButton.getId()) { | ||||
|                 onFullScreenButtonClicked(); | ||||
|  | ||||
|             } else if (v.getId() == switchBackgroundButton.getId()) { | ||||
|                 onPlayBackgroundButtonClicked(); | ||||
|  | ||||
|             } | ||||
|  | ||||
|             if (getCurrentState() != STATE_COMPLETED) { | ||||
| @@ -497,8 +537,15 @@ public final class MainVideoPlayer extends Activity { | ||||
|         private void onMoreOptionsClicked() { | ||||
|             if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called"); | ||||
|  | ||||
|             moreOptionsPopupMenu.show(); | ||||
|             isSomePopupMenuVisible = true; | ||||
|             if (secondaryControls.getVisibility() == View.VISIBLE) { | ||||
|                 moreOptionsButton.setImageDrawable(getResources().getDrawable( | ||||
|                         R.drawable.ic_expand_more_white_24dp)); | ||||
|                 animateView(secondaryControls, false, 200); | ||||
|             } else { | ||||
|                 moreOptionsButton.setImageDrawable(getResources().getDrawable( | ||||
|                         R.drawable.ic_expand_less_white_24dp)); | ||||
|                 animateView(secondaryControls, true, 200); | ||||
|             } | ||||
|             showControls(300); | ||||
|         } | ||||
|  | ||||
| @@ -522,6 +569,18 @@ public final class MainVideoPlayer extends Activity { | ||||
|             if (isPlaying()) hideControls(300, 0); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected int nextResizeMode(int currentResizeMode) { | ||||
|             switch (currentResizeMode) { | ||||
|                 case AspectRatioFrameLayout.RESIZE_MODE_FIT: | ||||
|                     return AspectRatioFrameLayout.RESIZE_MODE_FILL; | ||||
|                 case AspectRatioFrameLayout.RESIZE_MODE_FILL: | ||||
|                     return AspectRatioFrameLayout.RESIZE_MODE_ZOOM; | ||||
|                 default: | ||||
|                     return AspectRatioFrameLayout.RESIZE_MODE_FIT; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected int getDefaultResolutionIndex(final List<VideoStream> sortedVideos) { | ||||
|             return ListHelper.getDefaultResolutionIndex(context, sortedVideos); | ||||
| @@ -637,42 +696,6 @@ public final class MainVideoPlayer extends Activity { | ||||
|             setShuffleButton(shuffleButton, playQueue.isShuffled()); | ||||
|         } | ||||
|  | ||||
|         private void buildMoreOptionsMenu() { | ||||
|             this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions, | ||||
|                     moreOptionsPopupMenu.getMenu()); | ||||
|  | ||||
|             moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> { | ||||
|                 switch (menuItem.getItemId()) { | ||||
|                     case R.id.toggleOrientation: | ||||
|                         onScreenRotationClicked(); | ||||
|                         break; | ||||
|                     case R.id.switchPopup: | ||||
|                         onFullScreenButtonClicked(); | ||||
|                         break; | ||||
|                     case R.id.switchBackground: | ||||
|                         onPlayBackgroundButtonClicked(); | ||||
|                         break; | ||||
|                 } | ||||
|                 return false; | ||||
|             }); | ||||
|  | ||||
|             try { | ||||
|                 PopupMenuIconHacker.setShowPopupIcon(moreOptionsPopupMenu); | ||||
|             } catch (Exception e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|  | ||||
|             // fix icon theme | ||||
|             if(ThemeHelper.isLightThemeSelected(MainVideoPlayer.this)) { | ||||
|                 moreOptionsPopupMenu.getMenu() | ||||
|                         .findItem(R.id.toggleOrientation) | ||||
|                         .setIcon(R.drawable.ic_screen_rotation_black_24dp); | ||||
|                 moreOptionsPopupMenu.getMenu() | ||||
|                         .findItem(R.id.switchPopup) | ||||
|                         .setIcon(R.drawable.ic_fullscreen_exit_black_24dp); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         private void buildQueue() { | ||||
|             queueLayout = findViewById(R.id.playQueuePanel); | ||||
|  | ||||
|   | ||||
| @@ -49,8 +49,11 @@ import android.widget.RemoteViews; | ||||
| import android.widget.SeekBar; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.google.android.exoplayer2.C; | ||||
| import com.google.android.exoplayer2.PlaybackParameters; | ||||
| import com.google.android.exoplayer2.Player; | ||||
| import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; | ||||
| import com.google.android.exoplayer2.ui.SubtitleView; | ||||
|  | ||||
| import org.schabi.newpipe.BuildConfig; | ||||
| import org.schabi.newpipe.R; | ||||
| @@ -88,6 +91,8 @@ public final class PopupVideoPlayer extends Service { | ||||
|     private static final String POPUP_SAVED_X = "popup_saved_x"; | ||||
|     private static final String POPUP_SAVED_Y = "popup_saved_y"; | ||||
|  | ||||
|     private static final int MINIMUM_SHOW_EXTRA_WIDTH_DP = 300; | ||||
|  | ||||
|     private WindowManager windowManager; | ||||
|     private WindowManager.LayoutParams windowLayoutParams; | ||||
|     private GestureDetector gestureDetector; | ||||
| @@ -358,10 +363,12 @@ public final class PopupVideoPlayer extends Service { | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     protected class VideoPlayerImpl extends VideoPlayer { | ||||
|     protected class VideoPlayerImpl extends VideoPlayer implements View.OnLayoutChangeListener { | ||||
|         private TextView resizingIndicator; | ||||
|         private ImageButton fullScreenButton; | ||||
|  | ||||
|         private View extraOptionsView; | ||||
|  | ||||
|         @Override | ||||
|         public void handleIntent(Intent intent) { | ||||
|             super.handleIntent(intent); | ||||
| @@ -380,6 +387,29 @@ public final class PopupVideoPlayer extends Service { | ||||
|             resizingIndicator = rootView.findViewById(R.id.resizing_indicator); | ||||
|             fullScreenButton = rootView.findViewById(R.id.fullScreenButton); | ||||
|             fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked()); | ||||
|  | ||||
|             extraOptionsView = rootView.findViewById(R.id.extraOptionsView); | ||||
|             rootView.addOnLayoutChangeListener(this); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected void setupSubtitleView(@NonNull SubtitleView view, | ||||
|                                          @NonNull String captionSizeKey) { | ||||
|             float captionRatio = SubtitleView.DEFAULT_TEXT_SIZE_FRACTION; | ||||
|             if (captionSizeKey.equals(getString(R.string.smaller_caption_size_key))) { | ||||
|                 captionRatio *= 0.9; | ||||
|             } else if (captionSizeKey.equals(getString(R.string.larger_caption_size_key))) { | ||||
|                 captionRatio *= 1.1; | ||||
|             } | ||||
|             view.setFractionalTextSize(captionRatio); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onLayoutChange(final View view, int left, int top, int right, int bottom, | ||||
|                                    int oldLeft, int oldTop, int oldRight, int oldBottom) { | ||||
|             float widthDp = Math.abs(right - left) / getResources().getDisplayMetrics().density; | ||||
|             final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP ? View.VISIBLE : View.GONE; | ||||
|             extraOptionsView.setVisibility(visibility); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
| @@ -438,6 +468,15 @@ public final class PopupVideoPlayer extends Service { | ||||
|             if (isPlaying()) hideControls(500, 0); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         protected int nextResizeMode(int resizeMode) { | ||||
|             if (resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FILL) { | ||||
|                 return AspectRatioFrameLayout.RESIZE_MODE_FIT; | ||||
|             } else { | ||||
|                 return AspectRatioFrameLayout.RESIZE_MODE_FILL; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onStopTrackingTouch(SeekBar seekBar) { | ||||
|             super.onStopTrackingTouch(seekBar); | ||||
| @@ -642,8 +681,8 @@ public final class PopupVideoPlayer extends Service { | ||||
|         //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|         /*package-private*/ void enableVideoRenderer(final boolean enable) { | ||||
|             final int videoRendererIndex = getVideoRendererIndex(); | ||||
|             if (trackSelector != null && videoRendererIndex != -1) { | ||||
|             final int videoRendererIndex = getRendererIndex(C.TRACK_TYPE_VIDEO); | ||||
|             if (trackSelector != null && videoRendererIndex != RENDERER_UNAVAILABLE) { | ||||
|                 trackSelector.setRendererDisabled(videoRendererIndex, !enable); | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -29,8 +29,10 @@ import android.content.Intent; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.PorterDuff; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Handler; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.content.ContextCompat; | ||||
| @@ -46,17 +48,25 @@ import android.widget.SeekBar; | ||||
| import android.widget.TextView; | ||||
|  | ||||
| import com.google.android.exoplayer2.C; | ||||
| import com.google.android.exoplayer2.Format; | ||||
| import com.google.android.exoplayer2.Player; | ||||
| import com.google.android.exoplayer2.SimpleExoPlayer; | ||||
| import com.google.android.exoplayer2.source.MediaSource; | ||||
| import com.google.android.exoplayer2.source.MergingMediaSource; | ||||
| import com.google.android.exoplayer2.source.SingleSampleMediaSource; | ||||
| import com.google.android.exoplayer2.source.TrackGroup; | ||||
| import com.google.android.exoplayer2.source.TrackGroupArray; | ||||
| import com.google.android.exoplayer2.trackselection.TrackSelectionArray; | ||||
| import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; | ||||
| import com.google.android.exoplayer2.ui.SubtitleView; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.extractor.MediaFormat; | ||||
| import org.schabi.newpipe.extractor.Subtitles; | ||||
| import org.schabi.newpipe.extractor.stream.AudioStream; | ||||
| import org.schabi.newpipe.extractor.stream.StreamInfo; | ||||
| import org.schabi.newpipe.extractor.stream.VideoStream; | ||||
| import org.schabi.newpipe.player.helper.PlayerHelper; | ||||
| import org.schabi.newpipe.playlist.PlayQueueItem; | ||||
| import org.schabi.newpipe.util.AnimationUtils; | ||||
| import org.schabi.newpipe.util.ListHelper; | ||||
| @@ -64,6 +74,8 @@ import org.schabi.newpipe.util.ListHelper; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| import static com.google.android.exoplayer2.C.SELECTION_FLAG_AUTOSELECT; | ||||
| import static com.google.android.exoplayer2.C.TIME_UNSET; | ||||
| import static org.schabi.newpipe.player.helper.PlayerHelper.formatSpeed; | ||||
| import static org.schabi.newpipe.player.helper.PlayerHelper.getTimeString; | ||||
| import static org.schabi.newpipe.util.AnimationUtils.animateView; | ||||
| @@ -88,6 +100,7 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|     // Player | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|     protected static final int RENDERER_UNAVAILABLE = -1; | ||||
|     public static final int DEFAULT_CONTROLS_HIDE_TIME = 2000;  // 2 Seconds | ||||
|  | ||||
|     private ArrayList<VideoStream> availableStreams; | ||||
| @@ -123,6 +136,11 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|     private View topControlsRoot; | ||||
|     private TextView qualityTextView; | ||||
|  | ||||
|     private SubtitleView subtitleView; | ||||
|  | ||||
|     private TextView resizeView; | ||||
|     private TextView captionTextView; | ||||
|  | ||||
|     private ValueAnimator controlViewAnimator; | ||||
|     private Handler controlsVisibilityHandler = new Handler(); | ||||
|  | ||||
| @@ -133,6 +151,9 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|     private int playbackSpeedPopupMenuGroupId = 79; | ||||
|     private PopupMenu playbackSpeedPopupMenu; | ||||
|  | ||||
|     private int captionPopupMenuGroupId = 89; | ||||
|     private PopupMenu captionPopupMenu; | ||||
|  | ||||
|     /////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|     public VideoPlayer(String debugTag, Context context) { | ||||
| @@ -164,6 +185,17 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         this.topControlsRoot = rootView.findViewById(R.id.topControls); | ||||
|         this.qualityTextView = rootView.findViewById(R.id.qualityTextView); | ||||
|  | ||||
|         this.subtitleView = rootView.findViewById(R.id.subtitleView); | ||||
|         final String captionSizeKey = PreferenceManager.getDefaultSharedPreferences(context) | ||||
|                 .getString(context.getString(R.string.caption_size_key), | ||||
|                         context.getString(R.string.caption_size_default)); | ||||
|         setupSubtitleView(subtitleView, captionSizeKey); | ||||
|  | ||||
|         this.resizeView =  rootView.findViewById(R.id.resizeTextView); | ||||
|         resizeView.setText(PlayerHelper.resizeTypeOf(context, aspectRatioFrameLayout.getResizeMode())); | ||||
|  | ||||
|         this.captionTextView = rootView.findViewById(R.id.captionTextView); | ||||
|  | ||||
|         //this.aspectRatioFrameLayout.setAspectRatio(16.0f / 9.0f); | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) | ||||
| @@ -172,25 +204,37 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|  | ||||
|         this.qualityPopupMenu = new PopupMenu(context, qualityTextView); | ||||
|         this.playbackSpeedPopupMenu = new PopupMenu(context, playbackSpeedTextView); | ||||
|         this.captionPopupMenu = new PopupMenu(context, captionTextView); | ||||
|  | ||||
|         ((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel)).getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); | ||||
|  | ||||
|         ((ProgressBar) this.loadingPanel.findViewById(R.id.progressBarLoadingPanel)) | ||||
|                 .getIndeterminateDrawable().setColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY); | ||||
|     } | ||||
|  | ||||
|     protected abstract void setupSubtitleView(@NonNull SubtitleView view, | ||||
|                                               @NonNull String captionSizeKey); | ||||
|  | ||||
|     @Override | ||||
|     public void initListeners() { | ||||
|         super.initListeners(); | ||||
|         playbackSeekBar.setOnSeekBarChangeListener(this); | ||||
|         playbackSpeedTextView.setOnClickListener(this); | ||||
|         qualityTextView.setOnClickListener(this); | ||||
|         captionTextView.setOnClickListener(this); | ||||
|         resizeView.setOnClickListener(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void initPlayer() { | ||||
|         super.initPlayer(); | ||||
|  | ||||
|         // Setup video view | ||||
|         simpleExoPlayer.setVideoSurfaceView(surfaceView); | ||||
|         simpleExoPlayer.addVideoListener(this); | ||||
|  | ||||
|         // Setup subtitle view | ||||
|         simpleExoPlayer.addTextOutput(cues -> subtitleView.onCues(cues)); | ||||
|  | ||||
|         // Setup audio session with onboard equalizer | ||||
|         if (Build.VERSION.SDK_INT >= 21) { | ||||
|             trackSelector.setTunnelingAudioSessionId(C.generateAudioSessionIdV21(context)); | ||||
|         } | ||||
| @@ -236,6 +280,38 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         playbackSpeedPopupMenu.setOnDismissListener(this); | ||||
|     } | ||||
|  | ||||
|     private void buildCaptionMenu(final List<String> availableLanguages) { | ||||
|         if (captionPopupMenu == null) return; | ||||
|         captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId); | ||||
|  | ||||
|         // Add option for turning off caption | ||||
|         MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId, | ||||
|                 0, Menu.NONE, R.string.caption_none); | ||||
|         captionOffItem.setOnMenuItemClickListener(menuItem -> { | ||||
|             final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT); | ||||
|             if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) { | ||||
|                 trackSelector.setRendererDisabled(textRendererIndex, true); | ||||
|             } | ||||
|             return true; | ||||
|         }); | ||||
|  | ||||
|         // Add all available captions | ||||
|         for (int i = 0; i < availableLanguages.size(); i++) { | ||||
|             final String captionLanguage = availableLanguages.get(i); | ||||
|             MenuItem captionItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId, | ||||
|                     i + 1, Menu.NONE, captionLanguage); | ||||
|             captionItem.setOnMenuItemClickListener(menuItem -> { | ||||
|                 final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT); | ||||
|                 if (trackSelector != null && textRendererIndex != RENDERER_UNAVAILABLE) { | ||||
|                     trackSelector.setParameters(trackSelector.getParameters() | ||||
|                             .withPreferredTextLanguage(captionLanguage)); | ||||
|                     trackSelector.setRendererDisabled(textRendererIndex, false); | ||||
|                 } | ||||
|                 return true; | ||||
|             }); | ||||
|         } | ||||
|         captionPopupMenu.setOnDismissListener(this); | ||||
|     } | ||||
|     /*////////////////////////////////////////////////////////////////////////// | ||||
|     // Playback Listener | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
| @@ -251,7 +327,8 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         playbackSpeedTextView.setVisibility(View.GONE); | ||||
|  | ||||
|         if (info != null) { | ||||
|             final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, info.video_streams, info.video_only_streams, false); | ||||
|             final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context, | ||||
|                     info.video_streams, info.video_only_streams, false); | ||||
|             availableStreams = new ArrayList<>(videos); | ||||
|             if (playbackQuality == null) { | ||||
|                 selectedStreamIndex = getDefaultResolutionIndex(videos); | ||||
| @@ -280,13 +357,39 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         if (index < 0 || index >= videos.size()) return null; | ||||
|         final VideoStream video = videos.get(index); | ||||
|  | ||||
|         final MediaSource streamSource = buildMediaSource(video.getUrl(), MediaFormat.getSuffixById(video.format)); | ||||
|         final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams); | ||||
|         if (!video.isVideoOnly || audio == null) return streamSource; | ||||
|         List<MediaSource> mediaSources = new ArrayList<>(); | ||||
|         // Create video stream source | ||||
|         final MediaSource streamSource = buildMediaSource(video.getUrl(), | ||||
|                 MediaFormat.getSuffixById(video.getFormatId())); | ||||
|         mediaSources.add(streamSource); | ||||
|  | ||||
|         // Merge with audio stream in case if video does not contain audio | ||||
|         final MediaSource audioSource = buildMediaSource(audio.getUrl(), MediaFormat.getSuffixById(audio.format)); | ||||
|         return new MergingMediaSource(streamSource, audioSource); | ||||
|         // Create optional audio stream source | ||||
|         final AudioStream audio = ListHelper.getHighestQualityAudio(info.audio_streams); | ||||
|         if (video.isVideoOnly && audio != null) { | ||||
|             // Merge with audio stream in case if video does not contain audio | ||||
|             final MediaSource audioSource = buildMediaSource(audio.getUrl(), | ||||
|                     MediaFormat.getSuffixById(audio.getFormatId())); | ||||
|             mediaSources.add(audioSource); | ||||
|         } | ||||
|  | ||||
|         // Create subtitle sources | ||||
|         for (final Subtitles subtitle : info.getSubtitles()) { | ||||
|             final String mimeType = PlayerHelper.mimeTypesOf(subtitle.getFileType()); | ||||
|             if (mimeType == null) continue; | ||||
|  | ||||
|             final Format textFormat = Format.createTextSampleFormat(null, mimeType, | ||||
|                     SELECTION_FLAG_AUTOSELECT, PlayerHelper.captionLanguageOf(subtitle)); | ||||
|             final MediaSource textSource = new SingleSampleMediaSource( | ||||
|                     Uri.parse(subtitle.getURL()), cacheDataSourceFactory, textFormat, TIME_UNSET); | ||||
|             mediaSources.add(textSource); | ||||
|         } | ||||
|  | ||||
|         if (mediaSources.size() == 1) { | ||||
|             return mediaSources.get(0); | ||||
|         } else { | ||||
|             return new MergingMediaSource(mediaSources.toArray( | ||||
|                     new MediaSource[mediaSources.size()])); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /*////////////////////////////////////////////////////////////////////////// | ||||
| @@ -364,6 +467,12 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|     // ExoPlayer Video Listener | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|     @Override | ||||
|     public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { | ||||
|         super.onTracksChanged(trackGroups, trackSelections); | ||||
|         onTextTrackUpdate(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) { | ||||
|         if (DEBUG) { | ||||
| @@ -377,6 +486,57 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         animateView(surfaceForeground, false, 100); | ||||
|     } | ||||
|  | ||||
|     /*////////////////////////////////////////////////////////////////////////// | ||||
|     // ExoPlayer Track Updates | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|     private void onTextTrackUpdate() { | ||||
|         final int textRenderer = getRendererIndex(C.TRACK_TYPE_TEXT); | ||||
|  | ||||
|         if (captionTextView == null) return; | ||||
|         if (trackSelector == null || trackSelector.getCurrentMappedTrackInfo() == null || | ||||
|                 textRenderer == RENDERER_UNAVAILABLE) { | ||||
|             captionTextView.setVisibility(View.GONE); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         final TrackGroupArray textTracks = trackSelector.getCurrentMappedTrackInfo() | ||||
|                 .getTrackGroups(textRenderer); | ||||
|  | ||||
|         // Extract all loaded languages | ||||
|         List<String> availableLanguages = new ArrayList<>(textTracks.length); | ||||
|         for (int i = 0; i < textTracks.length; i++) { | ||||
|             final TrackGroup textTrack = textTracks.get(i); | ||||
|             if (textTrack.length > 0 && textTrack.getFormat(0) != null) { | ||||
|                 availableLanguages.add(textTrack.getFormat(0).language); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Normalize mismatching language strings | ||||
|         final String preferredLanguage = trackSelector.getParameters().preferredTextLanguage; | ||||
|         // Because ExoPlayer normalizes the preferred language string but not the text track | ||||
|         // language strings, some preferred language string will have the language name in lowercase | ||||
|         String formattedPreferredLanguage = null; | ||||
|         if (preferredLanguage != null) { | ||||
|             for (final String language : availableLanguages) { | ||||
|                 if (language.compareToIgnoreCase(preferredLanguage) == 0) { | ||||
|                     formattedPreferredLanguage = language; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // Build UI | ||||
|         buildCaptionMenu(availableLanguages); | ||||
|         if (trackSelector.getRendererDisabled(textRenderer) || formattedPreferredLanguage == null || | ||||
|                 !availableLanguages.contains(formattedPreferredLanguage)) { | ||||
|             captionTextView.setText(R.string.caption_none); | ||||
|         } else { | ||||
|             captionTextView.setText(formattedPreferredLanguage); | ||||
|         } | ||||
|         captionTextView.setVisibility(availableLanguages.isEmpty() ? View.GONE : View.VISIBLE); | ||||
|     } | ||||
|  | ||||
|     /*////////////////////////////////////////////////////////////////////////// | ||||
|     // General Player | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
| @@ -453,6 +613,10 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|             onQualitySelectorClicked(); | ||||
|         } else if (v.getId() == playbackSpeedTextView.getId()) { | ||||
|             onPlaybackSpeedClicked(); | ||||
|         } else if (v.getId() == resizeView.getId()) { | ||||
|             onResizeClicked(); | ||||
|         } else if (v.getId() == captionTextView.getId()) { | ||||
|             onCaptionClicked(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -516,6 +680,23 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         showControls(300); | ||||
|     } | ||||
|  | ||||
|     private void onCaptionClicked() { | ||||
|         if (DEBUG) Log.d(TAG, "onCaptionClicked() called"); | ||||
|         captionPopupMenu.show(); | ||||
|         isSomePopupMenuVisible = true; | ||||
|         showControls(300); | ||||
|     } | ||||
|  | ||||
|     private void onResizeClicked() { | ||||
|         if (getAspectRatioFrameLayout() != null && context != null) { | ||||
|             final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode(); | ||||
|             final int newResizeMode = nextResizeMode(currentResizeMode); | ||||
|             getAspectRatioFrameLayout().setResizeMode(newResizeMode); | ||||
|             getResizeView().setText(PlayerHelper.resizeTypeOf(context, newResizeMode)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected abstract int nextResizeMode(@AspectRatioFrameLayout.ResizeMode final int resizeMode); | ||||
|     /*////////////////////////////////////////////////////////////////////////// | ||||
|     // SeekBar Listener | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
| @@ -557,16 +738,16 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|     // Utils | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|     public int getVideoRendererIndex() { | ||||
|         if (simpleExoPlayer == null) return -1; | ||||
|     public int getRendererIndex(final int trackIndex) { | ||||
|         if (simpleExoPlayer == null) return RENDERER_UNAVAILABLE; | ||||
|  | ||||
|         for (int t = 0; t < simpleExoPlayer.getRendererCount(); t++) { | ||||
|             if (simpleExoPlayer.getRendererType(t) == C.TRACK_TYPE_VIDEO) { | ||||
|             if (simpleExoPlayer.getRendererType(t) == trackIndex) { | ||||
|                 return t; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return -1; | ||||
|         return RENDERER_UNAVAILABLE; | ||||
|     } | ||||
|  | ||||
|     public boolean isControlsVisible() { | ||||
| @@ -755,4 +936,15 @@ public abstract class VideoPlayer extends BasePlayer | ||||
|         return currentDisplaySeek; | ||||
|     } | ||||
|  | ||||
|     public SubtitleView getSubtitleView() { | ||||
|         return subtitleView; | ||||
|     } | ||||
|  | ||||
|     public TextView getResizeView() { | ||||
|         return resizeView; | ||||
|     } | ||||
|  | ||||
|     public TextView getCaptionTextView() { | ||||
|         return captionTextView; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -5,7 +5,12 @@ import android.content.SharedPreferences; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.support.annotation.NonNull; | ||||
|  | ||||
| import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; | ||||
| import com.google.android.exoplayer2.util.MimeTypes; | ||||
|  | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.extractor.Subtitles; | ||||
| import org.schabi.newpipe.extractor.stream.SubtitlesFormat; | ||||
|  | ||||
| import java.text.DecimalFormat; | ||||
| import java.text.NumberFormat; | ||||
| @@ -14,6 +19,12 @@ import java.util.Locale; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
|  | ||||
| import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FILL; | ||||
| import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT; | ||||
| import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT; | ||||
| import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH; | ||||
| import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM; | ||||
|  | ||||
| public class PlayerHelper { | ||||
|     private PlayerHelper() {} | ||||
|  | ||||
| @@ -46,6 +57,30 @@ public class PlayerHelper { | ||||
|         return pitchFormatter.format(pitch); | ||||
|     } | ||||
|  | ||||
|     public static String mimeTypesOf(final SubtitlesFormat format) { | ||||
|         switch (format) { | ||||
|             case VTT: return MimeTypes.TEXT_VTT; | ||||
|             case TTML: return MimeTypes.APPLICATION_TTML; | ||||
|             default: throw new IllegalArgumentException("Unrecognized mime type: " + format.name()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @NonNull | ||||
|     public static String captionLanguageOf(@NonNull final Subtitles subtitles) { | ||||
|         final String displayName = subtitles.getLocale().getDisplayName(subtitles.getLocale()); | ||||
|         return displayName + (subtitles.isAutoGenerated() ? " (auto-generated)" : ""); | ||||
|     } | ||||
|  | ||||
|     public static String resizeTypeOf(@NonNull final Context context, | ||||
|                                       @AspectRatioFrameLayout.ResizeMode final int resizeMode) { | ||||
|         switch (resizeMode) { | ||||
|             case RESIZE_MODE_FIT: return context.getResources().getString(R.string.resize_fit); | ||||
|             case RESIZE_MODE_FILL: return context.getResources().getString(R.string.resize_fill); | ||||
|             case RESIZE_MODE_ZOOM: return context.getResources().getString(R.string.resize_zoom); | ||||
|             default: throw new IllegalArgumentException("Unrecognized resize mode: " + resizeMode); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) { | ||||
|         return isResumeAfterAudioFocusGain(context, false); | ||||
|     } | ||||
|   | ||||
| @@ -30,6 +30,12 @@ | ||||
|  | ||||
|     </com.google.android.exoplayer2.ui.AspectRatioFrameLayout> | ||||
|  | ||||
|     <com.google.android.exoplayer2.ui.SubtitleView | ||||
|         android:id="@+id/subtitleView" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:layout_centerInParent="true" | ||||
|         android:layout_gravity="center"/> | ||||
|  | ||||
|     <ImageView | ||||
|         android:id="@+id/endScreen" | ||||
| @@ -139,13 +145,14 @@ | ||||
|                 android:layout_alignParentTop="true" | ||||
|                 android:background="@drawable/player_top_controls_bg" | ||||
|                 android:gravity="top" | ||||
|                 android:paddingBottom="70dp" | ||||
|                 android:paddingLeft="2dp" | ||||
|                 android:paddingRight="10dp" | ||||
|                 android:paddingTop="10dp" | ||||
|                 android:paddingBottom="10dp" | ||||
|                 android:paddingLeft="5dp" | ||||
|                 android:paddingRight="5dp" | ||||
|                 tools:ignore="RtlHardcoded"> | ||||
|  | ||||
|                 <LinearLayout | ||||
|                     android:id="@+id/metadataView" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_alignParentLeft="true" | ||||
| @@ -202,6 +209,7 @@ | ||||
|                     android:text="720p" | ||||
|                     android:textColor="@android:color/white" | ||||
|                     android:textStyle="bold" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="HardcodedText,RtlHardcoded"/> | ||||
|  | ||||
|                 <TextView | ||||
| @@ -215,6 +223,7 @@ | ||||
|                     android:minWidth="40dp" | ||||
|                     android:textColor="@android:color/white" | ||||
|                     android:textStyle="bold" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="RtlHardcoded,RtlSymmetry" | ||||
|                     tools:text="1x" /> | ||||
|  | ||||
| @@ -225,12 +234,12 @@ | ||||
|                     android:layout_marginLeft="2dp" | ||||
|                     android:layout_marginRight="2dp" | ||||
|                     android:layout_toLeftOf="@+id/moreOptionsButton" | ||||
|                     android:background="#00ffffff" | ||||
|                     android:clickable="true" | ||||
|                     android:focusable="true" | ||||
|                     android:padding="5dp" | ||||
|                     android:scaleType="fitXY" | ||||
|                     android:src="@drawable/list" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="ContentDescription,RtlHardcoded"/> | ||||
|  | ||||
|                 <ImageButton | ||||
| @@ -240,13 +249,109 @@ | ||||
|                     android:layout_alignParentRight="true" | ||||
|                     android:layout_marginLeft="2dp" | ||||
| 					android:padding="5dp" | ||||
|                     android:background="#00ffffff" | ||||
|                     android:clickable="true" | ||||
|                     android:focusable="true" | ||||
|                     android:scaleType="fitXY" | ||||
|                     android:src="@drawable/ic_more_vert_white_24dp" | ||||
|                     android:src="@drawable/ic_expand_more_white_24dp" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="ContentDescription,RtlHardcoded"/> | ||||
|             </RelativeLayout> | ||||
|  | ||||
|             <RelativeLayout | ||||
|                 android:id="@+id/secondaryControls" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" | ||||
|                 android:layout_below="@id/topControls" | ||||
|                 android:gravity="top" | ||||
|                 android:paddingLeft="5dp" | ||||
|                 android:paddingRight="5dp" | ||||
|                 android:visibility="gone" | ||||
|                 tools:ignore="RtlHardcoded" | ||||
|                 tools:visibility="visible"> | ||||
|  | ||||
|                 <TextView | ||||
|                     android:id="@+id/resizeTextView" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="35dp" | ||||
|                     android:layout_marginLeft="8dp" | ||||
|                     android:layout_marginRight="8dp" | ||||
|                     android:layout_alignParentLeft="true" | ||||
|                     android:gravity="center" | ||||
|                     android:minWidth="50dp" | ||||
|                     android:textColor="@android:color/white" | ||||
|                     android:textStyle="bold" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="HardcodedText,RtlHardcoded" | ||||
|                     tools:text="FIT"/> | ||||
|  | ||||
|                 <TextView | ||||
|                     android:id="@+id/captionTextView" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="wrap_content" | ||||
|                     android:layout_marginLeft="8dp" | ||||
|                     android:layout_marginRight="8dp" | ||||
|                     android:layout_toLeftOf="@id/switchBackground" | ||||
|                     android:layout_toRightOf="@id/resizeTextView" | ||||
|                     android:gravity="center|left" | ||||
|                     android:minHeight="35dp" | ||||
|                     android:minWidth="40dp" | ||||
|                     android:paddingLeft="2dp" | ||||
|                     android:paddingRight="2dp" | ||||
|                     android:textColor="@android:color/white" | ||||
|                     android:textStyle="bold" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="RelativeOverlap,RtlHardcoded" | ||||
|                     tools:text="English" /> | ||||
|  | ||||
|                 <ImageButton | ||||
|                     android:id="@+id/toggleOrientation" | ||||
|                     android:layout_width="30dp" | ||||
|                     android:layout_height="30dp" | ||||
|                     android:layout_marginLeft="2dp" | ||||
|                     android:layout_marginRight="2dp" | ||||
|                     android:layout_alignParentRight="true" | ||||
|                     android:layout_centerVertical="true" | ||||
|                     android:clickable="true" | ||||
|                     android:focusable="true" | ||||
|                     android:padding="5dp" | ||||
|                     android:scaleType="fitXY" | ||||
|                     android:src="@drawable/ic_screen_rotation_white" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     android:contentDescription="@string/toggle_orientation" | ||||
|                     tools:ignore="RtlHardcoded"/> | ||||
|  | ||||
|                 <ImageButton | ||||
|                     android:id="@+id/switchPopup" | ||||
|                     android:layout_width="30dp" | ||||
|                     android:layout_height="30dp" | ||||
|                     android:layout_marginLeft="2dp" | ||||
|                     android:layout_marginRight="2dp" | ||||
|                     android:layout_toLeftOf="@id/toggleOrientation" | ||||
|                     android:layout_centerVertical="true" | ||||
|                     android:clickable="true" | ||||
|                     android:focusable="true" | ||||
|                     android:scaleType="fitXY" | ||||
|                     android:src="@drawable/ic_fullscreen_exit_white" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     android:contentDescription="@string/switch_to_popup" | ||||
|                     tools:ignore="RtlHardcoded"/> | ||||
|  | ||||
|                 <ImageButton | ||||
|                     android:id="@+id/switchBackground" | ||||
|                     android:layout_width="30dp" | ||||
|                     android:layout_height="30dp" | ||||
|                     android:layout_marginLeft="2dp" | ||||
|                     android:layout_marginRight="2dp" | ||||
|                     android:layout_toLeftOf="@id/switchPopup" | ||||
|                     android:layout_centerVertical="true" | ||||
|                     android:clickable="true" | ||||
|                     android:focusable="true" | ||||
|                     android:padding="5dp" | ||||
|                     android:scaleType="fitXY" | ||||
|                     android:src="@drawable/ic_headset_white_24dp" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     android:contentDescription="@string/switch_to_background" | ||||
|                     tools:ignore="RtlHardcoded"/> | ||||
|             </RelativeLayout> | ||||
|  | ||||
|             <LinearLayout | ||||
| @@ -293,7 +398,6 @@ | ||||
|                     tools:ignore="HardcodedText" | ||||
|                     tools:text="1:23:49"/> | ||||
|             </LinearLayout> | ||||
|  | ||||
|         </RelativeLayout> | ||||
|  | ||||
|         <ImageButton | ||||
| @@ -379,7 +483,10 @@ | ||||
|     <RelativeLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:layout_alignParentTop="true" | ||||
|         android:layout_gravity="center" | ||||
|         android:layout_toEndOf="@+id/loading_panel" | ||||
|         android:layout_toRightOf="@+id/loading_panel" | ||||
|         tools:ignore="RtlHardcoded"> | ||||
|  | ||||
|         <TextView | ||||
| @@ -399,7 +506,7 @@ | ||||
|             android:visibility="gone" | ||||
|             tools:ignore="RtlHardcoded" | ||||
|             tools:text="Volume 0" | ||||
|             tools:visibility="visible"/> | ||||
|             tools:visibility="visible" /> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/brightnessTextView" | ||||
| @@ -418,7 +525,7 @@ | ||||
|             android:visibility="gone" | ||||
|             tools:ignore="RtlHardcoded" | ||||
|             tools:text="Brightness  0" | ||||
|             tools:visibility="visible"/> | ||||
|             tools:visibility="visible" /> | ||||
|  | ||||
|         <TextView | ||||
|             android:id="@+id/currentDisplaySeek" | ||||
| @@ -437,7 +544,7 @@ | ||||
|             android:visibility="gone" | ||||
|             tools:ignore="RtlHardcoded" | ||||
|             tools:text="1:06:29" | ||||
|             tools:visibility="visible"/> | ||||
|             tools:visibility="visible" /> | ||||
|     </RelativeLayout> | ||||
|  | ||||
| </RelativeLayout> | ||||
|   | ||||
| @@ -28,6 +28,10 @@ | ||||
|             android:layout_height="match_parent" | ||||
|             android:background="@android:color/black"/> | ||||
|  | ||||
|         <com.google.android.exoplayer2.ui.SubtitleView | ||||
|             android:id="@+id/subtitleView" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent"/> | ||||
|     </com.google.android.exoplayer2.ui.AspectRatioFrameLayout> | ||||
|  | ||||
|  | ||||
| @@ -70,6 +74,7 @@ | ||||
|                 android:padding="5dp" | ||||
|                 android:textColor="@android:color/white" | ||||
|                 android:textStyle="bold" | ||||
|                 android:background="?attr/selectableItemBackground" | ||||
|                 tools:ignore="RtlHardcoded,RtlSymmetry" | ||||
|                 tools:text="1080p60"/> | ||||
|  | ||||
| @@ -79,24 +84,61 @@ | ||||
|                 android:layout_height="30dp" | ||||
|                 android:layout_toRightOf="@+id/qualityTextView" | ||||
|                 android:gravity="center" | ||||
|                 android:padding="6dp" | ||||
|                 android:padding="5dp" | ||||
|                 android:textColor="@android:color/white" | ||||
|                 android:textStyle="bold" | ||||
|                 android:background="?attr/selectableItemBackground" | ||||
|                 tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry" | ||||
|                 tools:text="1.75x"/> | ||||
|  | ||||
|             <RelativeLayout | ||||
|                 android:id="@+id/extraOptionsView" | ||||
|                 android:layout_width="wrap_content" | ||||
|                 android:layout_height="30dp" | ||||
|                 android:layout_toRightOf="@+id/playbackSpeed" | ||||
|                 android:layout_toLeftOf="@id/fullScreenButton" | ||||
|                 android:visibility="gone"> | ||||
|  | ||||
|                 <TextView | ||||
|                     android:id="@+id/resizeTextView" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="match_parent" | ||||
|                     android:padding="5dp" | ||||
|                     android:layout_alignParentLeft="true" | ||||
|                     android:gravity="center" | ||||
|                     android:minWidth="50dp" | ||||
|                     android:textColor="@android:color/white" | ||||
|                     android:textStyle="bold" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="HardcodedText,RtlHardcoded" | ||||
|                     tools:text="FIT"/> | ||||
|  | ||||
|                 <TextView | ||||
|                     android:id="@+id/captionTextView" | ||||
|                     android:layout_width="wrap_content" | ||||
|                     android:layout_height="match_parent" | ||||
|                     android:padding="5dp" | ||||
|                     android:layout_toRightOf="@id/resizeTextView" | ||||
|                     android:gravity="center|left" | ||||
|                     android:minWidth="40dp" | ||||
|                     android:textColor="@android:color/white" | ||||
|                     android:textStyle="bold" | ||||
|                     android:background="?attr/selectableItemBackground" | ||||
|                     tools:ignore="RelativeOverlap,RtlHardcoded,RtlSymmetry" | ||||
|                     tools:text="English" /> | ||||
|             </RelativeLayout> | ||||
|  | ||||
|             <ImageButton | ||||
|                 android:id="@+id/fullScreenButton" | ||||
|                 android:layout_width="30dp" | ||||
|                 android:layout_height="30dp" | ||||
|                 android:layout_alignParentRight="true" | ||||
|                 android:background="#00ffffff" | ||||
|                 android:clickable="true" | ||||
|                 android:focusable="true" | ||||
|                 android:scaleType="fitCenter" | ||||
|                 android:background="?attr/selectableItemBackground" | ||||
|                 android:src="@drawable/ic_fullscreen_white" | ||||
|                 tools:ignore="ContentDescription,RtlHardcoded"/> | ||||
|  | ||||
|         </RelativeLayout> | ||||
|  | ||||
|         <!--Shadow Bottom Control--> | ||||
|   | ||||
| @@ -100,6 +100,25 @@ | ||||
|         <item>@string/black_theme_title</item> | ||||
|     </string-array> | ||||
|  | ||||
|     <!-- Caption Size --> | ||||
|     <string name="caption_size_key" translatable="false">caption_size_key</string> | ||||
|     <string name="caption_size_default" translatable="false">@string/normal_caption_size_key</string> | ||||
|  | ||||
|     <string name="smaller_caption_size_key" translatable="false">smaller_caption_size</string> | ||||
|     <string name="normal_caption_size_key" translatable="false">normal_caption_size</string> | ||||
|     <string name="larger_caption_size_key" translatable="false">larger_caption_size</string> | ||||
|  | ||||
|     <string-array name="caption_size_descriptions_list" translatable="false"> | ||||
|         <item>@string/smaller_caption_font_size</item> | ||||
|         <item>@string/normal_caption_font_size</item> | ||||
|         <item>@string/larger_caption_font_size</item> | ||||
|     </string-array> | ||||
|     <string-array name="caption_size_values_list" translatable="false"> | ||||
|         <item>@string/smaller_caption_size_key</item> | ||||
|         <item>@string/normal_caption_size_key</item> | ||||
|         <item>@string/larger_caption_size_key</item> | ||||
|     </string-array> | ||||
|  | ||||
|     <!-- Content & History --> | ||||
|     <string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string> | ||||
|     <string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string> | ||||
|   | ||||
| @@ -397,4 +397,17 @@ | ||||
|     <string name="playlist_add_stream_success">Added to playlist</string> | ||||
|     <string name="playlist_thumbnail_change_success">Playlist thumbnail changed</string> | ||||
|     <string name="playlist_delete_failure">Failed to delete playlist</string> | ||||
|  | ||||
|     <!-- Players --> | ||||
|     <string name="caption_none">No Caption</string> | ||||
|  | ||||
|     <string name="resize_fit">FIT</string> | ||||
|     <string name="resize_fill">FILL</string> | ||||
|     <string name="resize_zoom">ZOOM</string> | ||||
|  | ||||
|     <string name="caption_font_size_settings_title">Caption Font Size</string> | ||||
|     <string name="smaller_caption_font_size">Smaller Font</string> | ||||
|     <string name="normal_caption_font_size">Normal Font</string> | ||||
|     <string name="larger_caption_font_size">Larger Font</string> | ||||
|  | ||||
| </resources> | ||||
|   | ||||
| @@ -21,4 +21,12 @@ | ||||
|         android:key="@string/show_hold_to_append_key" | ||||
|         android:title="@string/show_hold_to_append_title" | ||||
|         android:summary="@string/show_hold_to_append_summary"/> | ||||
|  | ||||
|     <ListPreference | ||||
|         android:defaultValue="@string/caption_size_default" | ||||
|         android:entries="@array/caption_size_descriptions_list" | ||||
|         android:entryValues="@array/caption_size_values_list" | ||||
|         android:key="@string/caption_size_key" | ||||
|         android:summary="%s" | ||||
|         android:title="@string/caption_font_size_settings_title"/> | ||||
| </PreferenceScreen> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Christian Schabesberger
					Christian Schabesberger