Fourth block of fixes for review
- wrote more methods to PlayQueue. Now it supports internal history of played items with ability to play previous() item. Also it has equals() to check whether queues has the same content or not - backstack in fragment is more powerful now with help of PlayQueue's history and able to work great with playlists' PlayQueue and SinglePlayQueue at the same time - simplified logic inside fragment. Easy to understand. New PlayQueue will be added in backstack from only one place; less number of setInitialData() calls - BasePlayer now able to check PlayQueue and compare it with currently playing. And if it is the same queue it tries to not init() it twice. It gives possibility to have a great backstack in fragment since the same queue will not be played from two different instances and will not be added to backstack twice with duplicated history inside - better support of Player.STATE_IDLE - worked with layouts of player and made them better and more universal - service will be stopped when activity finishes by a user decision - fixed a problem related to ChannelPlayQueue and PlaylistPlayQueue in initial start of fragment - fixed crash in popup
This commit is contained in:
parent
e063967734
commit
a2d5314cf7
|
@ -7,7 +7,7 @@ import java.io.Serializable;
|
|||
class StackItem implements Serializable {
|
||||
private final int serviceId;
|
||||
private String title;
|
||||
private final String url;
|
||||
private String url;
|
||||
private final PlayQueue playQueue;
|
||||
|
||||
StackItem(int serviceId, String url, String title, PlayQueue playQueue) {
|
||||
|
@ -21,6 +21,10 @@ class StackItem implements Serializable {
|
|||
this.title = title;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ public class VideoDetailFragment
|
|||
@State
|
||||
protected PlayQueue playQueue;
|
||||
@State
|
||||
int bottomSheetState = BottomSheetBehavior.STATE_HIDDEN;
|
||||
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
||||
|
||||
private StreamInfo currentInfo;
|
||||
private Disposable currentWorker;
|
||||
|
@ -398,7 +398,8 @@ public class VideoDetailFragment
|
|||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
unbind();
|
||||
if (!activity.isFinishing()) unbind();
|
||||
else stopService();
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.unregisterOnSharedPreferenceChangeListener(this);
|
||||
|
@ -850,26 +851,6 @@ public class VideoDetailFragment
|
|||
*/
|
||||
protected final LinkedList<StackItem> stack = new LinkedList<>();
|
||||
|
||||
public void pushToStack(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "pushToStack() called with: serviceId = ["
|
||||
+ serviceId + "], videoUrl = [" + videoUrl + "], name = [" + name + "], playQueue = [" + playQueue + "]");
|
||||
}
|
||||
|
||||
if (stack.size() > 0
|
||||
&& stack.peek().getServiceId() == serviceId
|
||||
&& stack.peek().getUrl().equals(videoUrl)
|
||||
&& stack.peek().getPlayQueue().getClass().equals(playQueue.getClass())) {
|
||||
Log.d(TAG, "pushToStack() called with: serviceId == peek.serviceId = ["
|
||||
+ serviceId + "], videoUrl == peek.getUrl = [" + videoUrl + "]");
|
||||
return;
|
||||
} else {
|
||||
Log.d(TAG, "pushToStack() wasn't equal");
|
||||
}
|
||||
|
||||
stack.push(new StackItem(serviceId, videoUrl, name, playQueue));
|
||||
}
|
||||
|
||||
public void setTitleToUrl(int serviceId, String videoUrl, String name) {
|
||||
if (name != null && !name.isEmpty()) {
|
||||
for (StackItem stackItem : stack) {
|
||||
|
@ -885,12 +866,17 @@ public class VideoDetailFragment
|
|||
public boolean onBackPressed() {
|
||||
if (DEBUG) Log.d(TAG, "onBackPressed() called");
|
||||
|
||||
// If we are in fullscreen mode just exit from it via first back press
|
||||
if (player != null && player.isInFullscreen()) {
|
||||
player.onPause();
|
||||
restoreDefaultOrientation();
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we have something in history of played items we replay it here
|
||||
if (player != null && player.getPlayQueue().previous()) {
|
||||
return true;
|
||||
}
|
||||
// That means that we are on the start of the stack,
|
||||
// return false to let the MainActivity handle the onBack
|
||||
if (stack.size() <= 1) {
|
||||
|
@ -928,15 +914,15 @@ public class VideoDetailFragment
|
|||
}
|
||||
|
||||
public void selectAndLoadVideo(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
|
||||
boolean streamIsTheSame = videoUrl.equals(url) && currentInfo != null;
|
||||
setInitialData(serviceId, videoUrl, name, playQueue);
|
||||
|
||||
boolean streamIsTheSame = this.playQueue != null && this.playQueue.equals(playQueue);
|
||||
// Situation when user switches from players to main player. All needed data is here, we can start watching
|
||||
if (streamIsTheSame) {
|
||||
handleResult(currentInfo);
|
||||
//TODO not sure about usefulness of this line in the case when user switches from one player to another
|
||||
// handleResult(currentInfo);
|
||||
openVideoPlayer();
|
||||
return;
|
||||
}
|
||||
setInitialData(serviceId, videoUrl, name, playQueue);
|
||||
startLoading(false);
|
||||
}
|
||||
|
||||
|
@ -944,7 +930,6 @@ public class VideoDetailFragment
|
|||
if (DEBUG) Log.d(TAG, "prepareAndHandleInfo() called with: info = ["
|
||||
+ info + "], scrollToTop = [" + scrollToTop + "]");
|
||||
|
||||
setInitialData(info.getServiceId(), info.getUrl(), info.getName(), new SinglePlayQueue(info));
|
||||
showLoading();
|
||||
initTabs();
|
||||
|
||||
|
@ -1390,8 +1375,6 @@ public class VideoDetailFragment
|
|||
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(),
|
||||
playQueue == null ? new SinglePlayQueue(info) : playQueue);
|
||||
|
||||
pushToStack(serviceId, url, name, playQueue);
|
||||
|
||||
if(showRelatedStreams){
|
||||
if(null == relatedStreamsLayout){ //phone
|
||||
pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(info));
|
||||
|
@ -1627,6 +1610,20 @@ public class VideoDetailFragment
|
|||
// Player event listener
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onQueueUpdate(PlayQueue queue) {
|
||||
playQueue = queue;
|
||||
// This should be the only place where we push data to stack. It will allow to have live instance of PlayQueue with actual
|
||||
// information about deleted/added items inside Channel/Playlist queue and makes possible to have a history of played items
|
||||
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue))
|
||||
stack.push(new StackItem(serviceId, url, name, playQueue));
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
|
||||
+ serviceId + "], videoUrl = [" + url + "], name = [" + name + "], playQueue = [" + playQueue + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
|
||||
setOverlayPlayPauseImage();
|
||||
|
@ -1647,11 +1644,6 @@ public class VideoDetailFragment
|
|||
public void onProgressUpdate(int currentProgress, int duration, int bufferPercent) {
|
||||
// Progress updates every second even if media is paused. It's useless until playing
|
||||
if (!player.getPlayer().isPlaying() || playQueue == null) return;
|
||||
|
||||
// Update current progress in cached playQueue because playQueue in popup and background players
|
||||
// are different instances
|
||||
playQueue.setRecovery(playQueue.getIndex(), currentProgress);
|
||||
|
||||
showPlaybackProgress(currentProgress, duration);
|
||||
|
||||
// We don't want to interrupt playback and don't want to see notification if player is stopped
|
||||
|
@ -1672,6 +1664,14 @@ public class VideoDetailFragment
|
|||
|
||||
@Override
|
||||
public void onMetadataUpdate(StreamInfo info) {
|
||||
if (!stack.isEmpty()) {
|
||||
// When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue) every new played stream gives
|
||||
// new title and url. StackItem contains information about first played stream. Let's update it here
|
||||
StackItem peek = stack.peek();
|
||||
peek.setTitle(info.getName());
|
||||
peek.setUrl(info.getUrl());
|
||||
}
|
||||
|
||||
if (currentInfo == info) return;
|
||||
|
||||
currentInfo = info;
|
||||
|
@ -1865,7 +1865,7 @@ public class VideoDetailFragment
|
|||
case BottomSheetBehavior.STATE_COLLAPSED:
|
||||
// Re-enable clicks
|
||||
setOverlayElementsClickable(true);
|
||||
if (player != null && player.isInFullscreen() && player.isPlaying()) showSystemUi();
|
||||
if (player != null && player.isInFullscreen()) showSystemUi();
|
||||
break;
|
||||
case BottomSheetBehavior.STATE_DRAGGING:
|
||||
if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
|
||||
|
@ -1873,7 +1873,6 @@ public class VideoDetailFragment
|
|||
case BottomSheetBehavior.STATE_SETTLING:
|
||||
break;
|
||||
}
|
||||
Log.d(TAG, "onStateChanged: " + newState);
|
||||
}
|
||||
@Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
||||
setOverlayLook(appBarLayout, behavior, slideOffset);
|
||||
|
|
|
@ -274,6 +274,16 @@ public abstract class BasePlayer implements
|
|||
return;
|
||||
}
|
||||
|
||||
boolean same = playQueue != null && playQueue.equals(queue);
|
||||
|
||||
// Do not re-init the same PlayQueue. Save time
|
||||
if (same && !playQueue.isDisposed()) {
|
||||
// Player can have state = IDLE when playback is stopped or failed and we should retry() in this case
|
||||
if (simpleExoPlayer != null && simpleExoPlayer.getPlaybackState() == Player.STATE_IDLE)
|
||||
simpleExoPlayer.retry();
|
||||
return;
|
||||
}
|
||||
|
||||
final int repeatMode = intent.getIntExtra(REPEAT_MODE, getRepeatMode());
|
||||
final float playbackSpeed = intent.getFloatExtra(PLAYBACK_SPEED, getPlaybackSpeed());
|
||||
final float playbackPitch = intent.getFloatExtra(PLAYBACK_PITCH, getPlaybackPitch());
|
||||
|
@ -284,14 +294,17 @@ public abstract class BasePlayer implements
|
|||
if (simpleExoPlayer != null
|
||||
&& queue.size() == 1
|
||||
&& playQueue != null
|
||||
&& playQueue.size() == 1
|
||||
&& playQueue.getItem() != null
|
||||
&& queue.getItem().getUrl().equals(playQueue.getItem().getUrl())
|
||||
&& queue.getItem().getRecoveryPosition() != PlayQueueItem.RECOVERY_UNSET
|
||||
) {
|
||||
&& !same) {
|
||||
simpleExoPlayer.seekTo(playQueue.getIndex(), queue.getItem().getRecoveryPosition());
|
||||
return;
|
||||
|
||||
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false) && isPlaybackResumeEnabled()) {
|
||||
} else if (intent.getBooleanExtra(RESUME_PLAYBACK, false)
|
||||
&& isPlaybackResumeEnabled()
|
||||
&& !same) {
|
||||
final PlayQueueItem item = queue.getItem();
|
||||
if (item != null && item.getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) {
|
||||
stateLoader = recordManager.loadStreamState(item)
|
||||
|
@ -321,7 +334,8 @@ public abstract class BasePlayer implements
|
|||
}
|
||||
}
|
||||
// Good to go...
|
||||
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
||||
// In a case of equal PlayQueues we can re-init old one but only when it is disposed
|
||||
initPlayback(same ? playQueue : queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
||||
/*playOnInit=*/true);
|
||||
}
|
||||
|
||||
|
|
|
@ -126,6 +126,7 @@ public final class MainPlayer extends Service {
|
|||
|
||||
if (playerImpl.getPlayer() != null) {
|
||||
playerImpl.wasPlaying = playerImpl.getPlayer().getPlayWhenReady();
|
||||
// We can't pause the player here because it will make transition from one stream to a new stream not smooth
|
||||
playerImpl.getPlayer().stop(false);
|
||||
playerImpl.setRecovery();
|
||||
}
|
||||
|
|
|
@ -557,6 +557,10 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||
// Binding Service Listener
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onQueueUpdate(PlayQueue queue) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
|
||||
onStateChanged(state);
|
||||
|
|
|
@ -281,6 +281,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||
private void setupElementsVisibility() {
|
||||
if (popupPlayerSelected()) {
|
||||
fullscreenButton.setVisibility(View.VISIBLE);
|
||||
getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.GONE);
|
||||
getRootView().findViewById(R.id.metadataView).setVisibility(View.GONE);
|
||||
queueButton.setVisibility(View.GONE);
|
||||
moreOptionsButton.setVisibility(View.GONE);
|
||||
|
@ -294,10 +295,11 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||
openInBrowser.setVisibility(View.GONE);
|
||||
} else {
|
||||
fullscreenButton.setVisibility(View.GONE);
|
||||
getRootView().findViewById(R.id.spaceBeforeControls).setVisibility(View.VISIBLE);
|
||||
getRootView().findViewById(R.id.metadataView).setVisibility(View.VISIBLE);
|
||||
moreOptionsButton.setVisibility(View.VISIBLE);
|
||||
getTopControlsRoot().setOrientation(LinearLayout.VERTICAL);
|
||||
primaryControls.getLayoutParams().width = LinearLayout.LayoutParams.MATCH_PARENT;
|
||||
primaryControls.getLayoutParams().width = secondaryControls.getLayoutParams().width;
|
||||
secondaryControls.setVisibility(View.GONE);
|
||||
moreOptionsButton.setImageDrawable(service.getResources().getDrawable(
|
||||
R.drawable.ic_expand_more_white_24dp));
|
||||
|
@ -500,7 +502,13 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||
triggerProgressUpdate();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@Override
|
||||
protected void initPlayback(@NonNull PlayQueue queue, int repeatMode, float playbackSpeed, float playbackPitch, boolean playbackSkipSilence, boolean playOnReady) {
|
||||
super.initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence, playOnReady);
|
||||
updateQueue(queue);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Player Overrides
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
@ -1088,7 +1096,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||
}
|
||||
|
||||
private void showSystemUIPartially() {
|
||||
if (isInFullscreen()) {
|
||||
if (isInFullscreen() && getParentActivity() != null) {
|
||||
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
|
@ -1106,7 +1114,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||
* This method measures width and height of controls visible on screen. It ensures that controls will be side-by-side with
|
||||
* NavigationBar and notches but not under them. Tablets have only bottom NavigationBar
|
||||
* */
|
||||
void setControlsSize() {
|
||||
private void setControlsSize() {
|
||||
Point size = new Point();
|
||||
Display display = getRootView().getDisplay();
|
||||
if (display == null) return;
|
||||
|
@ -1479,6 +1487,15 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||
}
|
||||
}
|
||||
|
||||
private void updateQueue(PlayQueue queue) {
|
||||
if (fragmentListener != null) {
|
||||
fragmentListener.onQueueUpdate(queue);
|
||||
}
|
||||
if (activityListener != null) {
|
||||
activityListener.onQueueUpdate(queue);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateMetadata() {
|
||||
if (fragmentListener != null && getCurrentMetadata() != null) {
|
||||
fragmentListener.onMetadataUpdate(getCurrentMetadata().getMetadata());
|
||||
|
|
|
@ -4,8 +4,10 @@ package org.schabi.newpipe.player.event;
|
|||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
|
||||
public interface PlayerEventListener {
|
||||
void onQueueUpdate(PlayQueue queue);
|
||||
void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters);
|
||||
void onProgressUpdate(int currentProgress, int duration, int bufferPercent);
|
||||
void onMetadataUpdate(StreamInfo info);
|
||||
|
|
|
@ -46,17 +46,23 @@ public abstract class PlayQueue implements Serializable {
|
|||
|
||||
private ArrayList<PlayQueueItem> backup;
|
||||
private ArrayList<PlayQueueItem> streams;
|
||||
private ArrayList<PlayQueueItem> history;
|
||||
@NonNull private final AtomicInteger queueIndex;
|
||||
|
||||
private transient BehaviorSubject<PlayQueueEvent> eventBroadcast;
|
||||
private transient Flowable<PlayQueueEvent> broadcastReceiver;
|
||||
private transient Subscription reportingReactor;
|
||||
|
||||
private transient boolean disposed;
|
||||
|
||||
PlayQueue(final int index, final List<PlayQueueItem> startWith) {
|
||||
streams = new ArrayList<>();
|
||||
streams.addAll(startWith);
|
||||
history = new ArrayList<>();
|
||||
history.add(streams.get(index));
|
||||
|
||||
queueIndex = new AtomicInteger(index);
|
||||
disposed = false;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -88,6 +94,7 @@ public abstract class PlayQueue implements Serializable {
|
|||
eventBroadcast = null;
|
||||
broadcastReceiver = null;
|
||||
reportingReactor = null;
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -195,6 +202,7 @@ public abstract class PlayQueue implements Serializable {
|
|||
int newIndex = index;
|
||||
if (index < 0) newIndex = 0;
|
||||
if (index >= streams.size()) newIndex = isComplete() ? index % streams.size() : streams.size() - 1;
|
||||
if (oldIndex != newIndex) history.add(streams.get(newIndex));
|
||||
|
||||
queueIndex.set(newIndex);
|
||||
broadcast(new SelectEvent(oldIndex, newIndex));
|
||||
|
@ -267,6 +275,9 @@ public abstract class PlayQueue implements Serializable {
|
|||
|
||||
if (skippable) {
|
||||
queueIndex.incrementAndGet();
|
||||
if (streams.size() > queueIndex.get()) {
|
||||
history.add(streams.get(queueIndex.get()));
|
||||
}
|
||||
} else {
|
||||
removeInternal(index);
|
||||
}
|
||||
|
@ -292,7 +303,9 @@ public abstract class PlayQueue implements Serializable {
|
|||
final int backupIndex = backup.indexOf(getItem(removeIndex));
|
||||
backup.remove(backupIndex);
|
||||
}
|
||||
streams.remove(removeIndex);
|
||||
|
||||
history.remove(streams.remove(removeIndex));
|
||||
history.add(streams.get(queueIndex.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -366,6 +379,7 @@ public abstract class PlayQueue implements Serializable {
|
|||
streams.add(0, streams.remove(newIndex));
|
||||
}
|
||||
queueIndex.set(0);
|
||||
history.add(streams.get(0));
|
||||
|
||||
broadcast(new ReorderEvent(originIndex, queueIndex.get()));
|
||||
}
|
||||
|
@ -393,10 +407,52 @@ public abstract class PlayQueue implements Serializable {
|
|||
} else {
|
||||
queueIndex.set(0);
|
||||
}
|
||||
history.add(streams.get(queueIndex.get()));
|
||||
|
||||
broadcast(new ReorderEvent(originIndex, queueIndex.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects previous played item
|
||||
*
|
||||
* This method removes currently playing item from history and
|
||||
* starts playing the last item from history if it exists
|
||||
*
|
||||
* Returns true if history is not empty and the item can be played
|
||||
* */
|
||||
public synchronized boolean previous() {
|
||||
if (history.size() <= 1) return false;
|
||||
|
||||
history.remove(history.size() - 1);
|
||||
|
||||
PlayQueueItem last = history.remove(history.size() - 1);
|
||||
setIndex(indexOf(last));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two PlayQueues. Useful when a user switches players but queue is the same so
|
||||
* we don't have to do anything with new queue. This method also gives a chance to track history of items in a queue in
|
||||
* VideoDetailFragment without duplicating items from two identical queues
|
||||
* */
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (!(obj instanceof PlayQueue) || getStreams().size() != ((PlayQueue) obj).getStreams().size())
|
||||
return false;
|
||||
|
||||
PlayQueue other = (PlayQueue) obj;
|
||||
for (int i = 0; i < getStreams().size(); i++) {
|
||||
if (!getItem(i).getUrl().equals(other.getItem(i).getUrl()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isDisposed() {
|
||||
return disposed;
|
||||
}
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Rx Broadcast
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
|
|
@ -141,17 +141,29 @@
|
|||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:background="@drawable/player_top_controls_bg"
|
||||
android:layout_alignParentTop="true" />
|
||||
|
||||
<!-- It will be hidden in popup -->
|
||||
<Space
|
||||
android:id="@+id/spaceBeforeControls"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topControls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@drawable/player_top_controls_bg"
|
||||
android:orientation="vertical"
|
||||
android:gravity="top"
|
||||
android:paddingTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:layout_toStartOf="@id/fullScreenButton">
|
||||
android:paddingEnd="6dp"
|
||||
android:layout_toEndOf="@id/spaceBeforeControls"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/primaryControls"
|
||||
|
@ -161,7 +173,6 @@
|
|||
android:gravity="top"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="6dp"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -171,7 +182,6 @@
|
|||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="8dp"
|
||||
tools:ignore="RtlHardcoded"
|
||||
android:layout_weight="1">
|
||||
|
@ -274,8 +284,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible">
|
||||
|
@ -302,6 +310,8 @@
|
|||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center|left"
|
||||
android:minHeight="35dp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:minWidth="50dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold"
|
||||
|
@ -365,10 +375,11 @@
|
|||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:padding="6dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="@drawable/player_top_controls_bg"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitCenter"
|
||||
|
|
|
@ -139,17 +139,29 @@
|
|||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="30dp"
|
||||
android:background="@drawable/player_top_controls_bg"
|
||||
android:layout_alignParentTop="true" />
|
||||
|
||||
<!-- It will be hidden in popup -->
|
||||
<Space
|
||||
android:id="@+id/spaceBeforeControls"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="0dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/topControls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@drawable/player_top_controls_bg"
|
||||
android:orientation="vertical"
|
||||
android:gravity="top"
|
||||
android:paddingTop="4dp"
|
||||
android:baselineAligned="false"
|
||||
android:layout_toStartOf="@id/fullScreenButton">
|
||||
android:paddingEnd="6dp"
|
||||
android:layout_toEndOf="@id/spaceBeforeControls"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/primaryControls"
|
||||
|
@ -159,7 +171,6 @@
|
|||
android:gravity="top"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="6dp"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<LinearLayout
|
||||
|
@ -169,7 +180,6 @@
|
|||
android:gravity="top"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="8dp"
|
||||
tools:ignore="RtlHardcoded"
|
||||
android:layout_weight="1">
|
||||
|
@ -272,8 +282,6 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="top"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible">
|
||||
|
@ -300,6 +308,8 @@
|
|||
android:layout_marginEnd="8dp"
|
||||
android:gravity="center|left"
|
||||
android:minHeight="35dp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:minWidth="50dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textStyle="bold"
|
||||
|
@ -363,10 +373,11 @@
|
|||
android:id="@+id/fullScreenButton"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingTop="8dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginEnd="2dp"
|
||||
android:padding="6dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:background="@drawable/player_top_controls_bg"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitCenter"
|
||||
|
|
Loading…
Reference in New Issue