All players in one place
- main, background, popup players now connected via one service, one view, one fragment, one activity and one gesture listener - playback position is synchronized between players. Easy to switch from one to another - expandable player at the bottom of the screen with cool animation and additional features like long click to open channel of a video, play/pause/close buttons and swipe down to dismiss - in-player integrated buttons for opening in browser, playing with Kodi, sharing a video - better background playback that can be activated in settings. Allows to automatically switch to audio-only mode when going to background and then switching to video-mode when returning to the app.
This commit is contained in:
parent
f9e7873e54
commit
c45514b989
29 changed files with 4057 additions and 531 deletions
|
@ -43,6 +43,14 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".player.MainPlayer"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
||||||
|
</intent-filter>
|
||||||
|
</service>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".player.BackgroundPlayerActivity"
|
android:name=".player.BackgroundPlayerActivity"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
|
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.*;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -29,19 +28,8 @@ import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
import android.widget.*;
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Window;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.Spinner;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
@ -53,6 +41,7 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import com.google.android.material.navigation.NavigationView;
|
import com.google.android.material.navigation.NavigationView;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
@ -64,16 +53,10 @@ import org.schabi.newpipe.fragments.BackPressable;
|
||||||
import org.schabi.newpipe.fragments.MainFragment;
|
import org.schabi.newpipe.fragments.MainFragment;
|
||||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||||
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
import org.schabi.newpipe.fragments.list.search.SearchFragment;
|
||||||
|
import org.schabi.newpipe.player.VideoPlayer;
|
||||||
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PeertubeHelper;
|
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
|
||||||
import org.schabi.newpipe.util.TLSSocketFactoryCompat;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -470,12 +453,25 @@ public class MainActivity extends AppCompatActivity {
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (DEBUG) Log.d(TAG, "onBackPressed() called");
|
if (DEBUG) Log.d(TAG, "onBackPressed() called");
|
||||||
|
|
||||||
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
|
FrameLayout bottomSheetLayout = findViewById(R.id.fragment_player_holder);
|
||||||
// If current fragment implements BackPressable (i.e. can/wanna handle back press) delegate the back press to it
|
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
|
||||||
if (fragment instanceof BackPressable) {
|
|
||||||
if (((BackPressable) fragment).onBackPressed()) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN || bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||||
|
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
|
||||||
|
// If current fragment implements BackPressable (i.e. can/wanna handle back press) delegate the back press to it
|
||||||
|
if (fragment instanceof BackPressable) {
|
||||||
|
if (((BackPressable) fragment).onBackPressed()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Fragment fragmentPlayer = getSupportFragmentManager().findFragmentById(R.id.fragment_player_holder);
|
||||||
|
// If current fragment implements BackPressable (i.e. can/wanna handle back press) delegate the back press to it
|
||||||
|
if (fragmentPlayer instanceof BackPressable) {
|
||||||
|
if (!((BackPressable) fragmentPlayer).onBackPressed())
|
||||||
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
|
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
|
||||||
finish();
|
finish();
|
||||||
|
@ -494,7 +490,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
NavigationHelper.openDownloads(this);
|
NavigationHelper.openDownloads(this);
|
||||||
break;
|
break;
|
||||||
case PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE:
|
case PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE:
|
||||||
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
|
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_player_holder);
|
||||||
if (fragment instanceof VideoDetailFragment) {
|
if (fragment instanceof VideoDetailFragment) {
|
||||||
((VideoDetailFragment) fragment).openDownloadDialog();
|
((VideoDetailFragment) fragment).openDownloadDialog();
|
||||||
}
|
}
|
||||||
|
@ -595,6 +591,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (DEBUG) Log.d(TAG, "initFragments() called");
|
if (DEBUG) Log.d(TAG, "initFragments() called");
|
||||||
StateSaver.clearStateFiles();
|
StateSaver.clearStateFiles();
|
||||||
if (getIntent() != null && getIntent().hasExtra(Constants.KEY_LINK_TYPE)) {
|
if (getIntent() != null && getIntent().hasExtra(Constants.KEY_LINK_TYPE)) {
|
||||||
|
// When user watch a video inside popup and then tries to open the video in main player while the app is closed
|
||||||
|
// he will see a blank fragment on place of kiosk. Let's open it first
|
||||||
|
if (getSupportFragmentManager().getBackStackEntryCount() == 0)
|
||||||
|
NavigationHelper.openMainFragment(getSupportFragmentManager());
|
||||||
|
|
||||||
handleIntent(getIntent());
|
handleIntent(getIntent());
|
||||||
} else NavigationHelper.gotoMainFragment(getSupportFragmentManager());
|
} else NavigationHelper.gotoMainFragment(getSupportFragmentManager());
|
||||||
}
|
}
|
||||||
|
@ -643,7 +644,9 @@ public class MainActivity extends AppCompatActivity {
|
||||||
switch (((StreamingService.LinkType) intent.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
switch (((StreamingService.LinkType) intent.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
||||||
case STREAM:
|
case STREAM:
|
||||||
boolean autoPlay = intent.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
boolean autoPlay = intent.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
||||||
NavigationHelper.openVideoDetailFragment(getSupportFragmentManager(), serviceId, url, title, autoPlay);
|
final String intentCacheKey = intent.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY);
|
||||||
|
final PlayQueue playQueue = intentCacheKey != null ? SerializedCache.getInstance().take(intentCacheKey, PlayQueue.class) : null;
|
||||||
|
NavigationHelper.openVideoDetailFragment(getSupportFragmentManager(), serviceId, url, title, autoPlay, playQueue);
|
||||||
break;
|
break;
|
||||||
case CHANNEL:
|
case CHANNEL:
|
||||||
NavigationHelper.openChannelFragment(getSupportFragmentManager(),
|
NavigationHelper.openChannelFragment(getSupportFragmentManager(),
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||||
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
import org.schabi.newpipe.player.playqueue.ChannelPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||||
|
@ -581,7 +582,7 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
playQueue = new SinglePlayQueue((StreamInfo) info);
|
playQueue = new SinglePlayQueue((StreamInfo) info);
|
||||||
|
|
||||||
if (playerChoice.equals(videoPlayerKey)) {
|
if (playerChoice.equals(videoPlayerKey)) {
|
||||||
NavigationHelper.playOnMainPlayer(this, playQueue, true);
|
openMainPlayer(playQueue, choice);
|
||||||
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
||||||
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
|
NavigationHelper.enqueueOnBackgroundPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(popupPlayerKey)) {
|
} else if (playerChoice.equals(popupPlayerKey)) {
|
||||||
|
@ -594,7 +595,7 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
playQueue = info instanceof ChannelInfo ? new ChannelPlayQueue((ChannelInfo) info) : new PlaylistPlayQueue((PlaylistInfo) info);
|
playQueue = info instanceof ChannelInfo ? new ChannelPlayQueue((ChannelInfo) info) : new PlaylistPlayQueue((PlaylistInfo) info);
|
||||||
|
|
||||||
if (playerChoice.equals(videoPlayerKey)) {
|
if (playerChoice.equals(videoPlayerKey)) {
|
||||||
NavigationHelper.playOnMainPlayer(this, playQueue, true);
|
openMainPlayer(playQueue, choice);
|
||||||
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
} else if (playerChoice.equals(backgroundPlayerKey)) {
|
||||||
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
|
NavigationHelper.playOnBackgroundPlayer(this, playQueue, true);
|
||||||
} else if (playerChoice.equals(popupPlayerKey)) {
|
} else if (playerChoice.equals(popupPlayerKey)) {
|
||||||
|
@ -604,6 +605,16 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void openMainPlayer(PlayQueue playQueue, Choice choice) {
|
||||||
|
Intent intent = NavigationHelper.getPlayerIntent(this, MainActivity.class, playQueue, true);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.putExtra(Constants.KEY_LINK_TYPE, choice.linkType);
|
||||||
|
intent.putExtra(Constants.KEY_URL, choice.url);
|
||||||
|
intent.putExtra(Constants.KEY_TITLE, "");
|
||||||
|
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
||||||
|
this.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
class StackItem implements Serializable {
|
class StackItem implements Serializable {
|
||||||
private final int serviceId;
|
private final int serviceId;
|
||||||
private String title;
|
private String title;
|
||||||
private final String url;
|
private final String url;
|
||||||
|
private final PlayQueue playQueue;
|
||||||
|
|
||||||
StackItem(int serviceId, String url, String title) {
|
StackItem(int serviceId, String url, String title, PlayQueue playQueue) {
|
||||||
this.serviceId = serviceId;
|
this.serviceId = serviceId;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
this.playQueue = playQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTitle(String title) {
|
public void setTitle(String title) {
|
||||||
|
@ -29,6 +33,8 @@ class StackItem implements Serializable {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlayQueue getPlayQueue() { return playQueue; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getServiceId() + ":" + getUrl() + " > " + getTitle();
|
return getServiceId() + ":" + getUrl() + " > " + getTitle();
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,11 @@
|
||||||
package org.schabi.newpipe.player;
|
package org.schabi.newpipe.player;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
import org.schabi.newpipe.util.PermissionHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.player.BackgroundPlayer.ACTION_CLOSE;
|
import static org.schabi.newpipe.player.BackgroundPlayer.ACTION_CLOSE;
|
||||||
|
@ -24,20 +26,20 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Intent getBindIntent() {
|
public Intent getBindIntent() {
|
||||||
return new Intent(this, BackgroundPlayer.class);
|
return new Intent(this, MainPlayer.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startPlayerListener() {
|
public void startPlayerListener() {
|
||||||
if (player != null && player instanceof BackgroundPlayer.BasePlayerImpl) {
|
if (player instanceof VideoPlayerImpl) {
|
||||||
((BackgroundPlayer.BasePlayerImpl) player).setActivityListener(this);
|
((VideoPlayerImpl) player).setActivityListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopPlayerListener() {
|
public void stopPlayerListener() {
|
||||||
if (player != null && player instanceof BackgroundPlayer.BasePlayerImpl) {
|
if (player instanceof VideoPlayerImpl) {
|
||||||
((BackgroundPlayer.BasePlayerImpl) player).removeActivityListener(this);
|
((VideoPlayerImpl) player).removeActivityListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +58,28 @@ public final class BackgroundPlayerActivity extends ServicePlayerActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.player.setRecovery();
|
this.player.setRecovery();
|
||||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
NavigationHelper.playOnPopupPlayer(getApplicationContext(), player.playQueue, true);
|
||||||
getApplicationContext().startService(getSwitchIntent(PopupVideoPlayer.class));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (item.getItemId() == R.id.action_switch_background) {
|
||||||
|
this.player.setRecovery();
|
||||||
|
NavigationHelper.playOnBackgroundPlayer(getApplicationContext(), player.playQueue, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public void setupMenu(Menu menu) {
|
||||||
|
if(player == null) return;
|
||||||
|
|
||||||
|
menu.findItem(R.id.action_switch_popup).setVisible(!((VideoPlayerImpl)player).popupPlayerSelected());
|
||||||
|
menu.findItem(R.id.action_switch_background).setVisible(!((VideoPlayerImpl)player).audioPlayerSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
public Intent getPlayerShutdownIntent() {
|
public Intent getPlayerShutdownIntent() {
|
||||||
return new Intent(ACTION_CLOSE);
|
return new Intent(ACTION_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,6 +151,8 @@ public abstract class BasePlayer implements
|
||||||
public static final String RESUME_PLAYBACK = "resume_playback";
|
public static final String RESUME_PLAYBACK = "resume_playback";
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String SELECT_ON_APPEND = "select_on_append";
|
public static final String SELECT_ON_APPEND = "select_on_append";
|
||||||
|
@NonNull
|
||||||
|
public static final String PLAYER_TYPE = "player_type";
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Playback
|
// Playback
|
||||||
|
@ -182,6 +184,10 @@ public abstract class BasePlayer implements
|
||||||
protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
|
protected final static int PROGRESS_LOOP_INTERVAL_MILLIS = 500;
|
||||||
protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
|
protected final static int RECOVERY_SKIP_THRESHOLD_MILLIS = 3000; // 3 seconds
|
||||||
|
|
||||||
|
public final static int PLAYER_TYPE_VIDEO = 0;
|
||||||
|
public final static int PLAYER_TYPE_AUDIO = 1;
|
||||||
|
public final static int PLAYER_TYPE_POPUP = 2;
|
||||||
|
|
||||||
protected SimpleExoPlayer simpleExoPlayer;
|
protected SimpleExoPlayer simpleExoPlayer;
|
||||||
protected AudioReactor audioReactor;
|
protected AudioReactor audioReactor;
|
||||||
protected MediaSessionManager mediaSessionManager;
|
protected MediaSessionManager mediaSessionManager;
|
||||||
|
@ -290,12 +296,24 @@ public abstract class BasePlayer implements
|
||||||
if (item != null && item.getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) {
|
if (item != null && item.getRecoveryPosition() == PlayQueueItem.RECOVERY_UNSET) {
|
||||||
stateLoader = recordManager.loadStreamState(item)
|
stateLoader = recordManager.loadStreamState(item)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doFinally(() -> initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
// Do not place initPlayback() in doFinally() because it restarts playback after destroy()
|
||||||
/*playOnInit=*/true))
|
//.doFinally()
|
||||||
.subscribe(
|
.subscribe(
|
||||||
state -> queue.setRecovery(queue.getIndex(), state.getProgressTime()),
|
state -> {
|
||||||
|
queue.setRecovery(queue.getIndex(), state.getProgressTime());
|
||||||
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
||||||
|
/*playOnInit=*/true);
|
||||||
|
},
|
||||||
error -> {
|
error -> {
|
||||||
if (DEBUG) error.printStackTrace();
|
if (DEBUG) error.printStackTrace();
|
||||||
|
// In case any error we can start playback without history
|
||||||
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
||||||
|
/*playOnInit=*/true);
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
// Completed but not found in history
|
||||||
|
initPlayback(queue, repeatMode, playbackSpeed, playbackPitch, playbackSkipSilence,
|
||||||
|
/*playOnInit=*/true);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
databaseUpdateReactor.add(stateLoader);
|
databaseUpdateReactor.add(stateLoader);
|
||||||
|
@ -354,7 +372,7 @@ public abstract class BasePlayer implements
|
||||||
|
|
||||||
databaseUpdateReactor.clear();
|
databaseUpdateReactor.clear();
|
||||||
progressUpdateReactor.set(null);
|
progressUpdateReactor.set(null);
|
||||||
|
ImageLoader.getInstance().stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -931,6 +949,7 @@ public abstract class BasePlayer implements
|
||||||
}
|
}
|
||||||
|
|
||||||
simpleExoPlayer.setPlayWhenReady(true);
|
simpleExoPlayer.setPlayWhenReady(true);
|
||||||
|
savePlaybackState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
|
@ -939,6 +958,7 @@ public abstract class BasePlayer implements
|
||||||
|
|
||||||
audioReactor.abandonAudioFocus();
|
audioReactor.abandonAudioFocus();
|
||||||
simpleExoPlayer.setPlayWhenReady(false);
|
simpleExoPlayer.setPlayWhenReady(false);
|
||||||
|
savePlaybackState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPlayPause() {
|
public void onPlayPause() {
|
||||||
|
|
353
app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
Normal file
353
app/src/main/java/org/schabi/newpipe/player/MainPlayer.java
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
|
||||||
|
* BackgroundPlayer.java is part of NewPipe
|
||||||
|
*
|
||||||
|
* License: GPL-3.0+
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.schabi.newpipe.player;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowManager;
|
||||||
|
import androidx.core.app.NotificationCompat;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.RemoteViews;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.Player;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.BuildConfig;
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.player.helper.LockManager;
|
||||||
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One service for all players
|
||||||
|
*
|
||||||
|
* @author mauriciocolli
|
||||||
|
*/
|
||||||
|
public final class MainPlayer extends Service {
|
||||||
|
private static final String TAG = "MainPlayer";
|
||||||
|
private static final boolean DEBUG = BasePlayer.DEBUG;
|
||||||
|
|
||||||
|
private VideoPlayerImpl playerImpl;
|
||||||
|
private WindowManager windowManager;
|
||||||
|
private LockManager lockManager;
|
||||||
|
|
||||||
|
private final IBinder mBinder = new MainPlayer.LocalBinder();
|
||||||
|
|
||||||
|
public enum PlayerType {
|
||||||
|
VIDEO,
|
||||||
|
AUDIO,
|
||||||
|
POPUP
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Notification
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
static final int NOTIFICATION_ID = 123789;
|
||||||
|
private NotificationManager notificationManager;
|
||||||
|
private NotificationCompat.Builder notBuilder;
|
||||||
|
private RemoteViews notRemoteView;
|
||||||
|
private RemoteViews bigNotRemoteView;
|
||||||
|
|
||||||
|
static final String ACTION_CLOSE = "org.schabi.newpipe.player.MainPlayer.CLOSE";
|
||||||
|
static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.MainPlayer.PLAY_PAUSE";
|
||||||
|
static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.MainPlayer.OPEN_CONTROLS";
|
||||||
|
static final String ACTION_REPEAT = "org.schabi.newpipe.player.MainPlayer.REPEAT";
|
||||||
|
static final String ACTION_PLAY_NEXT = "org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_NEXT";
|
||||||
|
static final String ACTION_PLAY_PREVIOUS = "org.schabi.newpipe.player.MainPlayer.ACTION_PLAY_PREVIOUS";
|
||||||
|
static final String ACTION_FAST_REWIND = "org.schabi.newpipe.player.MainPlayer.ACTION_FAST_REWIND";
|
||||||
|
static final String ACTION_FAST_FORWARD = "org.schabi.newpipe.player.MainPlayer.ACTION_FAST_FORWARD";
|
||||||
|
|
||||||
|
private static final String SET_IMAGE_RESOURCE_METHOD = "setImageResource";
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Service's LifeCycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
if (DEBUG) Log.d(TAG, "onCreate() called");
|
||||||
|
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
|
||||||
|
lockManager = new LockManager(this);
|
||||||
|
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
|
||||||
|
|
||||||
|
ThemeHelper.setTheme(this);
|
||||||
|
createView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createView() {
|
||||||
|
View layout = View.inflate(this, R.layout.activity_main_player, null);
|
||||||
|
|
||||||
|
playerImpl = new VideoPlayerImpl(this);
|
||||||
|
playerImpl.setup(layout);
|
||||||
|
playerImpl.shouldUpdateOnProgress = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onStartCommand() called with: intent = [" + intent +
|
||||||
|
"], flags = [" + flags + "], startId = [" + startId + "]");
|
||||||
|
playerImpl.handleIntent(intent);
|
||||||
|
if (playerImpl.mediaSessionManager != null) {
|
||||||
|
playerImpl.mediaSessionManager.handleMediaButtonIntent(intent);
|
||||||
|
}
|
||||||
|
return START_NOT_STICKY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "stop() called");
|
||||||
|
|
||||||
|
if (playerImpl.getPlayer() != null) {
|
||||||
|
playerImpl.wasPlaying = playerImpl.getPlayer().getPlayWhenReady();
|
||||||
|
playerImpl.getPlayer().stop(false);
|
||||||
|
playerImpl.setRecovery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTaskRemoved(Intent rootIntent) {
|
||||||
|
super.onTaskRemoved(rootIntent);
|
||||||
|
onDestroy();
|
||||||
|
// Unload from memory completely
|
||||||
|
Runtime.getRuntime().halt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
if (DEBUG) Log.d(TAG, "destroy() called");
|
||||||
|
onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void attachBaseContext(Context base) {
|
||||||
|
super.attachBaseContext(AudioServiceLeakFix.preventLeakOf(base));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return mBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Actions
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
private void onClose() {
|
||||||
|
if (DEBUG) Log.d(TAG, "onClose() called");
|
||||||
|
|
||||||
|
if (lockManager != null) {
|
||||||
|
lockManager.releaseWifiAndCpu();
|
||||||
|
}
|
||||||
|
if (playerImpl != null) {
|
||||||
|
removeViewFromParent();
|
||||||
|
|
||||||
|
playerImpl.savePlaybackState();
|
||||||
|
playerImpl.stopActivityBinding();
|
||||||
|
playerImpl.destroy();
|
||||||
|
}
|
||||||
|
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
|
||||||
|
playerImpl = null;
|
||||||
|
lockManager = null;
|
||||||
|
|
||||||
|
stopForeground(true);
|
||||||
|
stopSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
boolean isLandscape() {
|
||||||
|
return getResources().getDisplayMetrics().heightPixels < getResources().getDisplayMetrics().widthPixels;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getView() {
|
||||||
|
if (playerImpl == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return playerImpl.getRootView();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeViewFromParent() {
|
||||||
|
if (getView().getParent() != null) {
|
||||||
|
if (playerImpl.getParentActivity() != null) {
|
||||||
|
// This means view was added to fragment
|
||||||
|
ViewGroup parent = (ViewGroup) getView().getParent();
|
||||||
|
parent.removeView(getView());
|
||||||
|
} else
|
||||||
|
// This means view was added by windowManager for popup player
|
||||||
|
windowManager.removeViewImmediate(getView());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Notification
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
void resetNotification() {
|
||||||
|
notBuilder = createNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
private NotificationCompat.Builder createNotification() {
|
||||||
|
notRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification);
|
||||||
|
bigNotRemoteView = new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification_expanded);
|
||||||
|
|
||||||
|
setupNotification(notRemoteView);
|
||||||
|
setupNotification(bigNotRemoteView);
|
||||||
|
|
||||||
|
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, getString(R.string.notification_channel_id))
|
||||||
|
.setOngoing(true)
|
||||||
|
.setSmallIcon(R.drawable.ic_newpipe_triangle_white)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
.setCustomContentView(notRemoteView)
|
||||||
|
.setCustomBigContentView(bigNotRemoteView);
|
||||||
|
builder.setPriority(NotificationCompat.PRIORITY_MAX);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupNotification(RemoteViews remoteViews) {
|
||||||
|
// Don't show anything until player is playing
|
||||||
|
if (playerImpl == null) return;
|
||||||
|
|
||||||
|
remoteViews.setTextViewText(R.id.notificationSongName, playerImpl.getVideoTitle());
|
||||||
|
remoteViews.setTextViewText(R.id.notificationArtist, playerImpl.getUploaderName());
|
||||||
|
remoteViews.setImageViewBitmap(R.id.notificationCover, playerImpl.getThumbnail());
|
||||||
|
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationStop,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
// Starts VideoDetailFragment or opens BackgroundPlayerActivity.
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
|
||||||
|
PendingIntent.getActivity(this, NOTIFICATION_ID, getIntentForNotification(), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
|
||||||
|
|
||||||
|
if (playerImpl.playQueue != null && playerImpl.playQueue.size() > 1) {
|
||||||
|
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_previous);
|
||||||
|
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_next);
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
} else {
|
||||||
|
remoteViews.setInt(R.id.notificationFRewind, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_rewind);
|
||||||
|
remoteViews.setInt(R.id.notificationFForward, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_fastforward);
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_FAST_REWIND), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
|
||||||
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_FAST_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
}
|
||||||
|
|
||||||
|
setRepeatModeIcon(remoteViews, playerImpl.getRepeatMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the notification, and the play/pause button in it.
|
||||||
|
* Used for changes on the remoteView
|
||||||
|
*
|
||||||
|
* @param drawableId if != -1, sets the drawable with that id on the play/pause button
|
||||||
|
*/
|
||||||
|
synchronized void updateNotification(int drawableId) {
|
||||||
|
//if (DEBUG) Log.d(TAG, "updateNotification() called with: drawableId = [" + drawableId + "]");
|
||||||
|
if (notBuilder == null) return;
|
||||||
|
if (drawableId != -1) {
|
||||||
|
if (notRemoteView != null) notRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||||
|
if (bigNotRemoteView != null) bigNotRemoteView.setImageViewResource(R.id.notificationPlayPause, drawableId);
|
||||||
|
}
|
||||||
|
notificationManager.notify(NOTIFICATION_ID, notBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMode) {
|
||||||
|
if (remoteViews == null) return;
|
||||||
|
|
||||||
|
switch (repeatMode) {
|
||||||
|
case Player.REPEAT_MODE_OFF:
|
||||||
|
remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_repeat_off);
|
||||||
|
break;
|
||||||
|
case Player.REPEAT_MODE_ONE:
|
||||||
|
remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_repeat_one);
|
||||||
|
break;
|
||||||
|
case Player.REPEAT_MODE_ALL:
|
||||||
|
remoteViews.setInt(R.id.notificationRepeat, SET_IMAGE_RESOURCE_METHOD, R.drawable.exo_controls_repeat_all);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Intent getIntentForNotification() {
|
||||||
|
Intent intent;
|
||||||
|
if (playerImpl.audioPlayerSelected() || playerImpl.popupPlayerSelected()) {
|
||||||
|
// Means we play in popup or audio only. Let's show BackgroundPlayerActivity
|
||||||
|
intent = NavigationHelper.getBackgroundPlayerActivityIntent(getApplicationContext());
|
||||||
|
} else {
|
||||||
|
// We are playing in fragment. Don't open another activity just show fragment. That's it
|
||||||
|
intent = NavigationHelper.getPlayerIntent(this, MainActivity.class, null, true);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.setAction(Intent.ACTION_MAIN);
|
||||||
|
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||||
|
}
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Getters
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
LockManager getLockManager() {
|
||||||
|
return lockManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationCompat.Builder getNotBuilder() {
|
||||||
|
return notBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteViews getBigNotRemoteView() {
|
||||||
|
return bigNotRemoteView;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoteViews getNotRemoteView() {
|
||||||
|
return notRemoteView;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class LocalBinder extends Binder {
|
||||||
|
|
||||||
|
public MainPlayer getService() {
|
||||||
|
return MainPlayer.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoPlayerImpl getPlayer() {
|
||||||
|
return MainPlayer.this.playerImpl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -546,7 +546,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
onPlayBackgroundButtonClicked();
|
onPlayBackgroundButtonClicked();
|
||||||
break;
|
break;
|
||||||
case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP:
|
case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP:
|
||||||
onFullScreenButtonClicked();
|
toggleFullscreen();
|
||||||
break;
|
break;
|
||||||
case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE:
|
case PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE:
|
||||||
default:
|
default:
|
||||||
|
@ -593,8 +593,8 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFullScreenButtonClicked() {
|
public void toggleFullscreen() {
|
||||||
super.onFullScreenButtonClicked();
|
super.toggleFullscreen();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
||||||
if (simpleExoPlayer == null) return;
|
if (simpleExoPlayer == null) return;
|
||||||
|
@ -678,7 +678,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
onScreenRotationClicked();
|
onScreenRotationClicked();
|
||||||
|
|
||||||
} else if (v.getId() == switchPopupButton.getId()) {
|
} else if (v.getId() == switchPopupButton.getId()) {
|
||||||
onFullScreenButtonClicked();
|
toggleFullscreen();
|
||||||
|
|
||||||
} else if (v.getId() == switchBackgroundButton.getId()) {
|
} else if (v.getId() == switchBackgroundButton.getId()) {
|
||||||
onPlayBackgroundButtonClicked();
|
onPlayBackgroundButtonClicked();
|
||||||
|
@ -746,7 +746,7 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
@Override
|
@Override
|
||||||
public void onPlaybackSpeedClicked() {
|
public void onPlaybackSpeedClicked() {
|
||||||
PlaybackParameterDialog
|
PlaybackParameterDialog
|
||||||
.newInstance(getPlaybackSpeed(), getPlaybackPitch(), getPlaybackSkipSilence())
|
.newInstance(getPlaybackSpeed(), getPlaybackPitch(), getPlaybackSkipSilence(), MainVideoPlayer.this)
|
||||||
.show(getSupportFragmentManager(), TAG);
|
.show(getSupportFragmentManager(), TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -909,6 +909,9 @@ public final class MainVideoPlayer extends AppCompatActivity
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hideSystemUIIfNeeded() { }
|
||||||
|
|
||||||
private void updatePlaybackButtons() {
|
private void updatePlaybackButtons() {
|
||||||
if (repeatButton == null || shuffleButton == null ||
|
if (repeatButton == null || shuffleButton == null ||
|
||||||
simpleExoPlayer == null || playQueue == null) return;
|
simpleExoPlayer == null || playQueue == null) return;
|
||||||
|
|
|
@ -285,7 +285,7 @@ public final class PopupVideoPlayer extends Service {
|
||||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
|
||||||
// Starts popup player activity -- attempts to unlock lockscreen
|
// Starts popup player activity -- attempts to unlock lockscreen
|
||||||
final Intent intent = NavigationHelper.getPopupPlayerActivityIntent(this);
|
final Intent intent = NavigationHelper.getBackgroundPlayerActivityIntent(this);
|
||||||
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
|
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
|
||||||
PendingIntent.getActivity(this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT));
|
PendingIntent.getActivity(this, NOTIFICATION_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT));
|
||||||
|
|
||||||
|
@ -513,7 +513,7 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.initViews(rootView);
|
super.initViews(rootView);
|
||||||
resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
|
resizingIndicator = rootView.findViewById(R.id.resizing_indicator);
|
||||||
fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
|
fullScreenButton = rootView.findViewById(R.id.fullScreenButton);
|
||||||
fullScreenButton.setOnClickListener(v -> onFullScreenButtonClicked());
|
fullScreenButton.setOnClickListener(v -> toggleFullscreen());
|
||||||
videoPlayPause = rootView.findViewById(R.id.videoPlayPause);
|
videoPlayPause = rootView.findViewById(R.id.videoPlayPause);
|
||||||
|
|
||||||
extraOptionsView = rootView.findViewById(R.id.extraOptionsView);
|
extraOptionsView = rootView.findViewById(R.id.extraOptionsView);
|
||||||
|
@ -552,8 +552,8 @@ public final class PopupVideoPlayer extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFullScreenButtonClicked() {
|
public void toggleFullscreen() {
|
||||||
super.onFullScreenButtonClicked();
|
super.toggleFullscreen();
|
||||||
|
|
||||||
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
if (DEBUG) Log.d(TAG, "onFullScreenButtonClicked() called");
|
||||||
|
|
||||||
|
@ -867,6 +867,9 @@ public final class PopupVideoPlayer extends Service {
|
||||||
super.hideControlsAndButton(duration, delay, videoPlayPause);
|
super.hideControlsAndButton(duration, delay, videoPlayPause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hideSystemUIIfNeeded() { }
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.schabi.newpipe.player;
|
package org.schabi.newpipe.player;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -50,13 +51,18 @@ public final class PopupVideoPlayerActivity extends ServicePlayerActivity {
|
||||||
if (item.getItemId() == R.id.action_switch_background) {
|
if (item.getItemId() == R.id.action_switch_background) {
|
||||||
this.player.setRecovery();
|
this.player.setRecovery();
|
||||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
||||||
getApplicationContext().startService(getSwitchIntent(BackgroundPlayer.class));
|
getApplicationContext().startService(getSwitchIntent(MainPlayer.class, MainPlayer.PlayerType.AUDIO));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public void setupMenu(Menu menu) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//@Override
|
||||||
public Intent getPlayerShutdownIntent() {
|
public Intent getPlayerShutdownIntent() {
|
||||||
return new Intent(ACTION_CLOSE);
|
return new Intent(ACTION_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,17 +26,17 @@ import android.widget.TextView;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
import org.schabi.newpipe.fragments.OnScrollBelowItemsListener;
|
||||||
|
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||||
import org.schabi.newpipe.player.event.PlayerEventListener;
|
import org.schabi.newpipe.player.event.PlayerEventListener;
|
||||||
import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
|
import org.schabi.newpipe.player.helper.PlaybackParameterDialog;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueAdapter;
|
import org.schabi.newpipe.player.playqueue.*;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.util.Constants;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItemBuilder;
|
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItemHolder;
|
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItemTouchCallback;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
@ -109,7 +109,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
|
|
||||||
public abstract boolean onPlayerOptionSelected(MenuItem item);
|
public abstract boolean onPlayerOptionSelected(MenuItem item);
|
||||||
|
|
||||||
public abstract Intent getPlayerShutdownIntent();
|
public abstract void setupMenu(Menu menu);
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Activity Lifecycle
|
// Activity Lifecycle
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -148,6 +148,13 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow to setup visibility of menuItems
|
||||||
|
@Override
|
||||||
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
|
setupMenu(menu);
|
||||||
|
return super.onPrepareOptionsMenu(menu);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
|
@ -166,8 +173,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_switch_main:
|
case R.id.action_switch_main:
|
||||||
this.player.setRecovery();
|
this.player.setRecovery();
|
||||||
getApplicationContext().sendBroadcast(getPlayerShutdownIntent());
|
getApplicationContext().startActivity(getSwitchIntent(MainActivity.class, MainPlayer.PlayerType.VIDEO));
|
||||||
getApplicationContext().startActivity(getSwitchIntent(MainVideoPlayer.class));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
|
return onPlayerOptionSelected(item) || super.onOptionsItemSelected(item);
|
||||||
|
@ -179,8 +185,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
unbind();
|
unbind();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Intent getSwitchIntent(final Class clazz) {
|
Intent getSwitchIntent(final Class clazz, final MainPlayer.PlayerType playerType) {
|
||||||
return NavigationHelper.getPlayerIntent(
|
Intent intent = NavigationHelper.getPlayerIntent(
|
||||||
getApplicationContext(),
|
getApplicationContext(),
|
||||||
clazz,
|
clazz,
|
||||||
this.player.getPlayQueue(),
|
this.player.getPlayQueue(),
|
||||||
|
@ -189,8 +195,15 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
this.player.getPlaybackPitch(),
|
this.player.getPlaybackPitch(),
|
||||||
this.player.getPlaybackSkipSilence(),
|
this.player.getPlaybackSkipSilence(),
|
||||||
null,
|
null,
|
||||||
false
|
true);
|
||||||
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.putExtra(Constants.KEY_LINK_TYPE, StreamingService.LinkType.STREAM);
|
||||||
|
intent.putExtra(Constants.KEY_URL, this.player.getVideoUrl());
|
||||||
|
intent.putExtra(Constants.KEY_TITLE, this.player.getVideoTitle());
|
||||||
|
intent.putExtra(VideoDetailFragment.AUTO_PLAY, true);
|
||||||
|
intent.putExtra(Constants.KEY_SERVICE_ID, this.player.getCurrentMetadata().getMetadata().getServiceId());
|
||||||
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, playerType);
|
||||||
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -236,6 +249,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
|
|
||||||
if (service instanceof PlayerServiceBinder) {
|
if (service instanceof PlayerServiceBinder) {
|
||||||
player = ((PlayerServiceBinder) service).getPlayerInstance();
|
player = ((PlayerServiceBinder) service).getPlayerInstance();
|
||||||
|
} else if (service instanceof MainPlayer.LocalBinder) {
|
||||||
|
player = ((MainPlayer.LocalBinder) service).getPlayer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (player == null || player.getPlayQueue() == null ||
|
if (player == null || player.getPlayQueue() == null ||
|
||||||
|
@ -474,7 +489,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||||
private void openPlaybackParameterDialog() {
|
private void openPlaybackParameterDialog() {
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(),
|
PlaybackParameterDialog.newInstance(player.getPlaybackSpeed(), player.getPlaybackPitch(),
|
||||||
player.getPlaybackSkipSilence()).show(getSupportFragmentManager(), getTag());
|
player.getPlaybackSkipSilence(), this).show(getSupportFragmentManager(), getTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -478,7 +478,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
super.onCompleted();
|
super.onCompleted();
|
||||||
|
|
||||||
showControls(500);
|
showControls(500);
|
||||||
animateView(endScreen, true, 800);
|
|
||||||
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
|
animateView(currentDisplaySeek, AnimationUtils.Type.SCALE_AND_ALPHA, false, 200);
|
||||||
loadingPanel.setVisibility(View.GONE);
|
loadingPanel.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
@ -575,11 +574,6 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
playbackSpeedTextView.setText(formatSpeed(getPlaybackSpeed()));
|
playbackSpeedTextView.setText(formatSpeed(getPlaybackSpeed()));
|
||||||
|
|
||||||
super.onPrepared(playWhenReady);
|
super.onPrepared(playWhenReady);
|
||||||
|
|
||||||
if (simpleExoPlayer.getCurrentPosition() != 0 && !isControlsVisible()) {
|
|
||||||
controlsVisibilityHandler.removeCallbacksAndMessages(null);
|
|
||||||
controlsVisibilityHandler.postDelayed(this::showControlsThenHide, DEFAULT_CONTROLS_DURATION);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -615,7 +609,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
if (loadedImage != null) endScreen.setImageBitmap(loadedImage);
|
if (loadedImage != null) endScreen.setImageBitmap(loadedImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onFullScreenButtonClicked() {
|
protected void toggleFullscreen() {
|
||||||
changeState(STATE_BLOCKED);
|
changeState(STATE_BLOCKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,7 +718,7 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
showControls(DEFAULT_CONTROLS_DURATION);
|
showControls(DEFAULT_CONTROLS_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onResizeClicked() {
|
void onResizeClicked() {
|
||||||
if (getAspectRatioFrameLayout() != null) {
|
if (getAspectRatioFrameLayout() != null) {
|
||||||
final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
|
final int currentResizeMode = getAspectRatioFrameLayout().getResizeMode();
|
||||||
final int newResizeMode = nextResizeMode(currentResizeMode);
|
final int newResizeMode = nextResizeMode(currentResizeMode);
|
||||||
|
@ -888,6 +882,9 @@ public abstract class VideoPlayer extends BasePlayer
|
||||||
animateView(controlsRoot, false,duration);
|
animateView(controlsRoot, false,duration);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void hideSystemUIIfNeeded();
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Getters and Setters
|
// Getters and Setters
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
1552
app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
Normal file
1552
app/src/main/java/org/schabi/newpipe/player/VideoPlayerImpl.java
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,47 @@
|
||||||
|
package org.schabi.newpipe.player.event;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
public class CustomBottomSheetBehavior extends BottomSheetBehavior {
|
||||||
|
|
||||||
|
public CustomBottomSheetBehavior(Context context, AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent event) {
|
||||||
|
// Without overriding scrolling will not work in detail_content_root_layout
|
||||||
|
ViewGroup controls = child.findViewById(R.id.detail_content_root_layout);
|
||||||
|
if (controls != null) {
|
||||||
|
Rect rect = new Rect();
|
||||||
|
controls.getGlobalVisibleRect(rect);
|
||||||
|
if (rect.contains((int) event.getX(), (int) event.getY())) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Without overriding scrolling will not work on relatedStreamsLayout
|
||||||
|
ViewGroup relatedStreamsLayout = child.findViewById(R.id.relatedStreamsLayout);
|
||||||
|
if (relatedStreamsLayout != null) {
|
||||||
|
Rect rect = new Rect();
|
||||||
|
relatedStreamsLayout.getGlobalVisibleRect(rect);
|
||||||
|
if (rect.contains((int) event.getX(), (int) event.getY())) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ViewGroup playQueue = child.findViewById(R.id.playQueue);
|
||||||
|
if (playQueue != null) {
|
||||||
|
Rect rect = new Rect();
|
||||||
|
playQueue.getGlobalVisibleRect(rect);
|
||||||
|
if (rect.contains((int) event.getX(), (int) event.getY())) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onInterceptTouchEvent(parent, child, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,462 @@
|
||||||
|
package org.schabi.newpipe.player.event;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.*;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.player.BasePlayer;
|
||||||
|
import org.schabi.newpipe.player.MainPlayer;
|
||||||
|
import org.schabi.newpipe.player.VideoPlayerImpl;
|
||||||
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.player.BasePlayer.*;
|
||||||
|
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_DURATION;
|
||||||
|
import static org.schabi.newpipe.player.VideoPlayer.DEFAULT_CONTROLS_HIDE_TIME;
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.Type.SCALE_AND_ALPHA;
|
||||||
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
|
public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener implements View.OnTouchListener {
|
||||||
|
private static final String TAG = ".PlayerGestureListener";
|
||||||
|
private static final boolean DEBUG = BasePlayer.DEBUG;
|
||||||
|
|
||||||
|
private VideoPlayerImpl playerImpl;
|
||||||
|
private MainPlayer service;
|
||||||
|
|
||||||
|
private int initialPopupX, initialPopupY;
|
||||||
|
|
||||||
|
private boolean isMovingInMain, isMovingInPopup;
|
||||||
|
|
||||||
|
private boolean isResizing;
|
||||||
|
|
||||||
|
private int tossFlingVelocity;
|
||||||
|
|
||||||
|
private final boolean isVolumeGestureEnabled;
|
||||||
|
private final boolean isBrightnessGestureEnabled;
|
||||||
|
private final int maxVolume;
|
||||||
|
private static final int MOVEMENT_THRESHOLD = 40;
|
||||||
|
|
||||||
|
|
||||||
|
public PlayerGestureListener(final VideoPlayerImpl playerImpl, final MainPlayer service) {
|
||||||
|
this.playerImpl = playerImpl;
|
||||||
|
this.service = service;
|
||||||
|
this.tossFlingVelocity = PlayerHelper.getTossFlingVelocity(service);
|
||||||
|
|
||||||
|
isVolumeGestureEnabled = PlayerHelper.isVolumeGestureEnabled(service);
|
||||||
|
isBrightnessGestureEnabled = PlayerHelper.isBrightnessGestureEnabled(service);
|
||||||
|
maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Main and popup players' gesture listeners is too different.
|
||||||
|
* So it will be better to have different implementations of them
|
||||||
|
* */
|
||||||
|
@Override
|
||||||
|
public boolean onDoubleTap(MotionEvent e) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onDoubleTap() called with: e = [" + e + "]" + "rawXy = " + e.getRawX() + ", " + e.getRawY() + ", xy = " + e.getX() + ", " + e.getY());
|
||||||
|
|
||||||
|
if (playerImpl.popupPlayerSelected()) return onDoubleTapInPopup(e);
|
||||||
|
else return onDoubleTapInMain(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
|
||||||
|
|
||||||
|
if (playerImpl.popupPlayerSelected()) return onSingleTapConfirmedInPopup(e);
|
||||||
|
else return onSingleTapConfirmedInMain(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDown(MotionEvent e) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onDown() called with: e = [" + e + "]");
|
||||||
|
|
||||||
|
if (playerImpl.popupPlayerSelected()) return onDownInPopup(e);
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void onLongPress(MotionEvent e) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onLongPress() called with: e = [" + e + "]");
|
||||||
|
|
||||||
|
if (playerImpl.popupPlayerSelected()) onLongPressInPopup(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
|
||||||
|
if (playerImpl.popupPlayerSelected()) return onScrollInPopup(initialEvent, movingEvent, distanceX, distanceY);
|
||||||
|
else return onScrollInMain(initialEvent, movingEvent, distanceX, distanceY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onFling() called with velocity: dX=[" + velocityX + "], dY=[" + velocityY + "]");
|
||||||
|
|
||||||
|
if (playerImpl.popupPlayerSelected()) return onFlingInPopup(e1, e2, velocityX, velocityY);
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
//noinspection PointlessBooleanExpression,ConstantConditions
|
||||||
|
if (DEBUG && false) Log.d(TAG, "onTouch() called with: v = [" + v + "], event = [" + event + "]");
|
||||||
|
|
||||||
|
if (playerImpl.popupPlayerSelected()) return onTouchInPopup(v, event);
|
||||||
|
else return onTouchInMain(v, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Main player listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private boolean onDoubleTapInMain(MotionEvent e) {
|
||||||
|
if (e.getX() > playerImpl.getRootView().getWidth() * 2 / 3) {
|
||||||
|
playerImpl.onFastForward();
|
||||||
|
} else if (e.getX() < playerImpl.getRootView().getWidth() / 3) {
|
||||||
|
playerImpl.onFastRewind();
|
||||||
|
} else {
|
||||||
|
playerImpl.getPlayPauseButton().performClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean onSingleTapConfirmedInMain(MotionEvent e) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onSingleTapConfirmed() called with: e = [" + e + "]");
|
||||||
|
|
||||||
|
if (playerImpl.getCurrentState() == BasePlayer.STATE_BLOCKED) return true;
|
||||||
|
|
||||||
|
if (playerImpl.isControlsVisible()) {
|
||||||
|
playerImpl.hideControls(150, 0);
|
||||||
|
} else {
|
||||||
|
if (playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
|
||||||
|
playerImpl.showControls(0);
|
||||||
|
} else {
|
||||||
|
playerImpl.showControlsThenHide();
|
||||||
|
}
|
||||||
|
if (playerImpl.isInFullscreen()) {
|
||||||
|
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||||
|
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||||
|
| View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||||
|
playerImpl.getParentActivity().getWindow().getDecorView().setSystemUiVisibility(visibility);
|
||||||
|
playerImpl.getParentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
||||||
|
playerImpl.getParentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onScrollInMain(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
|
||||||
|
if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) return false;
|
||||||
|
|
||||||
|
//noinspection PointlessBooleanExpression
|
||||||
|
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
|
||||||
|
", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" +
|
||||||
|
", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" +
|
||||||
|
", distanceXy = [" + distanceX + ", " + distanceY + "]");
|
||||||
|
|
||||||
|
final boolean insideThreshold = Math.abs(movingEvent.getY() - initialEvent.getY()) <= MOVEMENT_THRESHOLD;
|
||||||
|
if (!isMovingInMain && (insideThreshold || Math.abs(distanceX) > Math.abs(distanceY))
|
||||||
|
|| playerImpl.getCurrentState() == BasePlayer.STATE_COMPLETED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
isMovingInMain = true;
|
||||||
|
|
||||||
|
boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
|
||||||
|
boolean acceptVolumeArea = acceptAnyArea || initialEvent.getX() > playerImpl.getRootView().getWidth() / 2;
|
||||||
|
boolean acceptBrightnessArea = acceptAnyArea || !acceptVolumeArea;
|
||||||
|
|
||||||
|
if (isVolumeGestureEnabled && acceptVolumeArea) {
|
||||||
|
playerImpl.getVolumeProgressBar().incrementProgressBy((int) distanceY);
|
||||||
|
float currentProgressPercent =
|
||||||
|
(float) playerImpl.getVolumeProgressBar().getProgress() / playerImpl.getMaxGestureLength();
|
||||||
|
int currentVolume = (int) (maxVolume * currentProgressPercent);
|
||||||
|
playerImpl.getAudioReactor().setVolume(currentVolume);
|
||||||
|
|
||||||
|
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
|
||||||
|
|
||||||
|
final int resId =
|
||||||
|
currentProgressPercent <= 0 ? R.drawable.ic_volume_off_white_72dp
|
||||||
|
: currentProgressPercent < 0.25 ? R.drawable.ic_volume_mute_white_72dp
|
||||||
|
: currentProgressPercent < 0.75 ? R.drawable.ic_volume_down_white_72dp
|
||||||
|
: R.drawable.ic_volume_up_white_72dp;
|
||||||
|
|
||||||
|
playerImpl.getVolumeImageView().setImageDrawable(
|
||||||
|
AppCompatResources.getDrawable(service, resId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (playerImpl.getVolumeRelativeLayout().getVisibility() != View.VISIBLE) {
|
||||||
|
animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, true, 200);
|
||||||
|
}
|
||||||
|
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||||
|
playerImpl.getBrightnessRelativeLayout().setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
} else if (isBrightnessGestureEnabled && acceptBrightnessArea) {
|
||||||
|
Activity parent = playerImpl.getParentActivity();
|
||||||
|
if (parent == null) return true;
|
||||||
|
|
||||||
|
Window window = parent.getWindow();
|
||||||
|
|
||||||
|
playerImpl.getBrightnessProgressBar().incrementProgressBy((int) distanceY);
|
||||||
|
float currentProgressPercent =
|
||||||
|
(float) playerImpl.getBrightnessProgressBar().getProgress() / playerImpl.getMaxGestureLength();
|
||||||
|
WindowManager.LayoutParams layoutParams = window.getAttributes();
|
||||||
|
layoutParams.screenBrightness = currentProgressPercent;
|
||||||
|
window.setAttributes(layoutParams);
|
||||||
|
|
||||||
|
if (DEBUG) Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " + currentProgressPercent);
|
||||||
|
|
||||||
|
final int resId =
|
||||||
|
currentProgressPercent < 0.25 ? R.drawable.ic_brightness_low_white_72dp
|
||||||
|
: currentProgressPercent < 0.75 ? R.drawable.ic_brightness_medium_white_72dp
|
||||||
|
: R.drawable.ic_brightness_high_white_72dp;
|
||||||
|
|
||||||
|
playerImpl.getBrightnessImageView().setImageDrawable(
|
||||||
|
AppCompatResources.getDrawable(service, resId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (playerImpl.getBrightnessRelativeLayout().getVisibility() != View.VISIBLE) {
|
||||||
|
animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, true, 200);
|
||||||
|
}
|
||||||
|
if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||||
|
playerImpl.getVolumeRelativeLayout().setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onScrollEndInMain() {
|
||||||
|
if (DEBUG) Log.d(TAG, "onScrollEnd() called");
|
||||||
|
|
||||||
|
if (playerImpl.getVolumeRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||||
|
animateView(playerImpl.getVolumeRelativeLayout(), SCALE_AND_ALPHA, false, 200, 200);
|
||||||
|
}
|
||||||
|
if (playerImpl.getBrightnessRelativeLayout().getVisibility() == View.VISIBLE) {
|
||||||
|
animateView(playerImpl.getBrightnessRelativeLayout(), SCALE_AND_ALPHA, false, 200, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
|
||||||
|
playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onTouchInMain(View v, MotionEvent event) {
|
||||||
|
playerImpl.getGestureDetector().onTouchEvent(event);
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_UP && isMovingInMain) {
|
||||||
|
isMovingInMain = false;
|
||||||
|
onScrollEndInMain();
|
||||||
|
}
|
||||||
|
// This hack allows to stop receiving touch events on appbar while touching video player view
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
v.getParent().requestDisallowInterceptTouchEvent(playerImpl.isInFullscreen());
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
v.getParent().requestDisallowInterceptTouchEvent(false);
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Popup player listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
private boolean onDoubleTapInPopup(MotionEvent e) {
|
||||||
|
if (playerImpl == null || !playerImpl.isPlaying()) return false;
|
||||||
|
|
||||||
|
playerImpl.hideControls(0, 0);
|
||||||
|
|
||||||
|
if (e.getX() > playerImpl.getPopupWidth() / 2) {
|
||||||
|
playerImpl.onFastForward();
|
||||||
|
} else {
|
||||||
|
playerImpl.onFastRewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onSingleTapConfirmedInPopup(MotionEvent e) {
|
||||||
|
if (playerImpl == null || playerImpl.getPlayer() == null) return false;
|
||||||
|
if (playerImpl.isControlsVisible()) {
|
||||||
|
playerImpl.hideControls(100, 100);
|
||||||
|
} else {
|
||||||
|
playerImpl.showControlsThenHide();
|
||||||
|
|
||||||
|
}
|
||||||
|
playerImpl.onPlayPause();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onDownInPopup(MotionEvent e) {
|
||||||
|
// Fix popup position when the user touch it, it may have the wrong one
|
||||||
|
// because the soft input is visible (the draggable area is currently resized).
|
||||||
|
playerImpl.checkPopupPositionBounds(playerImpl.getCloseOverlayView().getWidth(), playerImpl.getCloseOverlayView().getHeight());
|
||||||
|
|
||||||
|
initialPopupX = playerImpl.getPopupLayoutParams().x;
|
||||||
|
initialPopupY = playerImpl.getPopupLayoutParams().y;
|
||||||
|
playerImpl.setPopupWidth(playerImpl.getPopupLayoutParams().width);
|
||||||
|
playerImpl.setPopupHeight(playerImpl.getPopupLayoutParams().height);
|
||||||
|
return super.onDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onLongPressInPopup(MotionEvent e) {
|
||||||
|
playerImpl.updateScreenSize();
|
||||||
|
playerImpl.checkPopupPositionBounds();
|
||||||
|
playerImpl.updatePopupSize((int) playerImpl.getScreenWidth(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onScrollInPopup(MotionEvent initialEvent, MotionEvent movingEvent, float distanceX, float distanceY) {
|
||||||
|
if (isResizing || playerImpl == null) return super.onScroll(initialEvent, movingEvent, distanceX, distanceY);
|
||||||
|
|
||||||
|
if (!isMovingInPopup) {
|
||||||
|
animateView(playerImpl.getCloseOverlayButton(), true, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
isMovingInPopup = true;
|
||||||
|
|
||||||
|
float diffX = (int) (movingEvent.getRawX() - initialEvent.getRawX()), posX = (int) (initialPopupX + diffX);
|
||||||
|
float diffY = (int) (movingEvent.getRawY() - initialEvent.getRawY()), posY = (int) (initialPopupY + diffY);
|
||||||
|
|
||||||
|
if (posX > (playerImpl.getScreenWidth() - playerImpl.getPopupWidth())) posX = (int) (playerImpl.getScreenWidth() - playerImpl.getPopupWidth());
|
||||||
|
else if (posX < 0) posX = 0;
|
||||||
|
|
||||||
|
if (posY > (playerImpl.getScreenHeight() - playerImpl.getPopupHeight())) posY = (int) (playerImpl.getScreenHeight() - playerImpl.getPopupHeight());
|
||||||
|
else if (posY < 0) posY = 0;
|
||||||
|
|
||||||
|
playerImpl.getPopupLayoutParams().x = (int) posX;
|
||||||
|
playerImpl.getPopupLayoutParams().y = (int) posY;
|
||||||
|
|
||||||
|
final View closingOverlayView = playerImpl.getClosingOverlayView();
|
||||||
|
if (playerImpl.isInsideClosingRadius(movingEvent)) {
|
||||||
|
if (closingOverlayView.getVisibility() == View.GONE) {
|
||||||
|
animateView(closingOverlayView, true, 250);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (closingOverlayView.getVisibility() == View.VISIBLE) {
|
||||||
|
animateView(closingOverlayView, false, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection PointlessBooleanExpression
|
||||||
|
if (DEBUG && false) {
|
||||||
|
Log.d(TAG, "PopupVideoPlayer.onScroll = " +
|
||||||
|
", e1.getRaw = [" + initialEvent.getRawX() + ", " + initialEvent.getRawY() + "]" + ", e1.getX,Y = [" + initialEvent.getX() + ", " + initialEvent.getY() + "]" +
|
||||||
|
", e2.getRaw = [" + movingEvent.getRawX() + ", " + movingEvent.getRawY() + "]" + ", e2.getX,Y = [" + movingEvent.getX() + ", " + movingEvent.getY() + "]" +
|
||||||
|
", distanceX,Y = [" + distanceX + ", " + distanceY + "]" +
|
||||||
|
", posX,Y = [" + posX + ", " + posY + "]" +
|
||||||
|
", popupW,H = [" + playerImpl.getPopupWidth() + " x " + playerImpl.getPopupHeight() + "]");
|
||||||
|
}
|
||||||
|
playerImpl.windowManager.updateViewLayout(playerImpl.getRootView(), playerImpl.getPopupLayoutParams());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onScrollEndInPopup(MotionEvent event) {
|
||||||
|
if (playerImpl == null) return;
|
||||||
|
if (playerImpl.isControlsVisible() && playerImpl.getCurrentState() == STATE_PLAYING) {
|
||||||
|
playerImpl.hideControls(DEFAULT_CONTROLS_DURATION, DEFAULT_CONTROLS_HIDE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerImpl.isInsideClosingRadius(event)) {
|
||||||
|
playerImpl.closePopup();
|
||||||
|
} else {
|
||||||
|
animateView(playerImpl.getClosingOverlayView(), false, 0);
|
||||||
|
|
||||||
|
if (!playerImpl.isPopupClosing) {
|
||||||
|
animateView(playerImpl.getCloseOverlayButton(), false, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onFlingInPopup(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||||
|
if (playerImpl == null) return false;
|
||||||
|
|
||||||
|
final float absVelocityX = Math.abs(velocityX);
|
||||||
|
final float absVelocityY = Math.abs(velocityY);
|
||||||
|
if (Math.max(absVelocityX, absVelocityY) > tossFlingVelocity) {
|
||||||
|
if (absVelocityX > tossFlingVelocity) playerImpl.getPopupLayoutParams().x = (int) velocityX;
|
||||||
|
if (absVelocityY > tossFlingVelocity) playerImpl.getPopupLayoutParams().y = (int) velocityY;
|
||||||
|
playerImpl.checkPopupPositionBounds();
|
||||||
|
playerImpl.windowManager.updateViewLayout(playerImpl.getRootView(), playerImpl.getPopupLayoutParams());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean onTouchInPopup(View v, MotionEvent event) {
|
||||||
|
playerImpl.getGestureDetector().onTouchEvent(event);
|
||||||
|
if (playerImpl == null) return false;
|
||||||
|
if (event.getPointerCount() == 2 && !isMovingInPopup && !isResizing) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onTouch() 2 finger pointer detected, enabling resizing.");
|
||||||
|
playerImpl.showAndAnimateControl(-1, true);
|
||||||
|
playerImpl.getLoadingPanel().setVisibility(View.GONE);
|
||||||
|
|
||||||
|
playerImpl.hideControls(0, 0);
|
||||||
|
animateView(playerImpl.getCurrentDisplaySeek(), false, 0, 0);
|
||||||
|
animateView(playerImpl.getResizingIndicator(), true, 200, 0);
|
||||||
|
isResizing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_MOVE && !isMovingInPopup && isResizing) {
|
||||||
|
if (DEBUG) Log.d(TAG, "onTouch() ACTION_MOVE > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
|
||||||
|
return handleMultiDrag(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
if (DEBUG)
|
||||||
|
Log.d(TAG, "onTouch() ACTION_UP > v = [" + v + "], e1.getRaw = [" + event.getRawX() + ", " + event.getRawY() + "]");
|
||||||
|
if (isMovingInPopup) {
|
||||||
|
isMovingInPopup = false;
|
||||||
|
onScrollEndInPopup(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isResizing) {
|
||||||
|
isResizing = false;
|
||||||
|
animateView(playerImpl.getResizingIndicator(), false, 100, 0);
|
||||||
|
playerImpl.changeState(playerImpl.getCurrentState());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!playerImpl.isPopupClosing) {
|
||||||
|
playerImpl.savePositionAndSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v.performClick();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean handleMultiDrag(final MotionEvent event) {
|
||||||
|
if (event.getPointerCount() != 2) return false;
|
||||||
|
|
||||||
|
final float firstPointerX = event.getX(0);
|
||||||
|
final float secondPointerX = event.getX(1);
|
||||||
|
|
||||||
|
final float diff = Math.abs(firstPointerX - secondPointerX);
|
||||||
|
if (firstPointerX > secondPointerX) {
|
||||||
|
// second pointer is the anchor (the leftmost pointer)
|
||||||
|
playerImpl.getPopupLayoutParams().x = (int) (event.getRawX() - diff);
|
||||||
|
} else {
|
||||||
|
// first pointer is the anchor
|
||||||
|
playerImpl.getPopupLayoutParams().x = (int) event.getRawX();
|
||||||
|
}
|
||||||
|
|
||||||
|
playerImpl.checkPopupPositionBounds();
|
||||||
|
playerImpl.updateScreenSize();
|
||||||
|
|
||||||
|
final int width = (int) Math.min(playerImpl.getScreenWidth(), diff);
|
||||||
|
playerImpl.updatePopupSize(width, -1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.schabi.newpipe.player.event;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
|
|
||||||
|
public interface PlayerServiceEventListener extends PlayerEventListener {
|
||||||
|
void onFullscreenStateChanged(boolean fullscreen);
|
||||||
|
|
||||||
|
void onMoreOptionsLongClicked();
|
||||||
|
|
||||||
|
void onPlayerError(ExoPlaybackException error);
|
||||||
|
|
||||||
|
boolean isFragmentStopped();
|
||||||
|
|
||||||
|
void hideSystemUIIfNeeded();
|
||||||
|
}
|
|
@ -80,8 +80,10 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
|
|
||||||
public static PlaybackParameterDialog newInstance(final double playbackTempo,
|
public static PlaybackParameterDialog newInstance(final double playbackTempo,
|
||||||
final double playbackPitch,
|
final double playbackPitch,
|
||||||
final boolean playbackSkipSilence) {
|
final boolean playbackSkipSilence,
|
||||||
|
Callback callback) {
|
||||||
PlaybackParameterDialog dialog = new PlaybackParameterDialog();
|
PlaybackParameterDialog dialog = new PlaybackParameterDialog();
|
||||||
|
dialog.callback = callback;
|
||||||
dialog.initialTempo = playbackTempo;
|
dialog.initialTempo = playbackTempo;
|
||||||
dialog.initialPitch = playbackPitch;
|
dialog.initialPitch = playbackPitch;
|
||||||
|
|
||||||
|
@ -99,9 +101,9 @@ public class PlaybackParameterDialog extends DialogFragment {
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context) {
|
public void onAttach(Context context) {
|
||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
if (context != null && context instanceof Callback) {
|
if (context instanceof Callback) {
|
||||||
callback = (Callback) context;
|
callback = (Callback) context;
|
||||||
} else {
|
} else if (callback == null) {
|
||||||
dismiss();
|
dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
|
import android.database.ContentObserver;
|
||||||
|
import android.os.Handler;
|
||||||
|
|
||||||
|
public class SettingsContentObserver extends ContentObserver {
|
||||||
|
private OnChangeListener listener;
|
||||||
|
|
||||||
|
public interface OnChangeListener {
|
||||||
|
void onSettingsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingsContentObserver(Handler handler, OnChangeListener listener) {
|
||||||
|
super(handler);
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deliverSelfNotifications() {
|
||||||
|
return super.deliverSelfNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChange(boolean selfChange) {
|
||||||
|
super.onChange(selfChange);
|
||||||
|
if (listener != null)
|
||||||
|
listener.onSettingsChanged();
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
@ -44,14 +45,9 @@ import org.schabi.newpipe.local.history.StatisticsPlaylistFragment;
|
||||||
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
|
import org.schabi.newpipe.local.playlist.LocalPlaylistFragment;
|
||||||
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
import org.schabi.newpipe.local.subscription.SubscriptionFragment;
|
||||||
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
|
import org.schabi.newpipe.local.subscription.SubscriptionsImportFragment;
|
||||||
import org.schabi.newpipe.player.BackgroundPlayer;
|
import org.schabi.newpipe.player.*;
|
||||||
import org.schabi.newpipe.player.BackgroundPlayerActivity;
|
|
||||||
import org.schabi.newpipe.player.BasePlayer;
|
|
||||||
import org.schabi.newpipe.player.MainVideoPlayer;
|
|
||||||
import org.schabi.newpipe.player.PopupVideoPlayer;
|
|
||||||
import org.schabi.newpipe.player.PopupVideoPlayerActivity;
|
|
||||||
import org.schabi.newpipe.player.VideoPlayer;
|
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.settings.SettingsActivity;
|
import org.schabi.newpipe.settings.SettingsActivity;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -78,6 +74,9 @@ public class NavigationHelper {
|
||||||
if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
|
if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality);
|
||||||
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback);
|
intent.putExtra(VideoPlayer.RESUME_PLAYBACK, resumePlayback);
|
||||||
|
|
||||||
|
int playerType = intent.getIntExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_VIDEO);
|
||||||
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, playerType);
|
||||||
|
|
||||||
return intent;
|
return intent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,10 +116,13 @@ public class NavigationHelper {
|
||||||
.putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence);
|
.putExtra(BasePlayer.PLAYBACK_SKIP_SILENCE, playbackSkipSilence);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void playOnMainPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
public static void playOnMainPlayer(final AppCompatActivity activity, final PlayQueue queue, final boolean resumePlayback) {
|
||||||
final Intent playerIntent = getPlayerIntent(context, MainVideoPlayer.class, queue, resumePlayback);
|
playOnMainPlayer(activity.getSupportFragmentManager(), queue, resumePlayback);
|
||||||
playerIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
}
|
||||||
context.startActivity(playerIntent);
|
|
||||||
|
public static void playOnMainPlayer(final FragmentManager fragmentManager, final PlayQueue queue, boolean autoPlay) {
|
||||||
|
PlayQueueItem currentStream = queue.getItem();
|
||||||
|
NavigationHelper.openVideoDetailFragment(fragmentManager, currentStream.getServiceId(), currentStream.getUrl(), currentStream.getTitle(), autoPlay, queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void playOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
public static void playOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
||||||
|
@ -130,12 +132,16 @@ public class NavigationHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.popup_playing_toast, Toast.LENGTH_SHORT).show();
|
||||||
startService(context, getPlayerIntent(context, PopupVideoPlayer.class, queue, resumePlayback));
|
Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
|
||||||
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP);
|
||||||
|
startService(context, intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void playOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
public static void playOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
||||||
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show();
|
||||||
startService(context, getPlayerIntent(context, BackgroundPlayer.class, queue, resumePlayback));
|
Intent intent = getPlayerIntent(context, MainPlayer.class, queue, resumePlayback);
|
||||||
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO);
|
||||||
|
startService(context, intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
||||||
|
@ -149,8 +155,9 @@ public class NavigationHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.makeText(context, R.string.popup_playing_append, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.popup_playing_append, Toast.LENGTH_SHORT).show();
|
||||||
startService(context,
|
Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
|
||||||
getPlayerEnqueueIntent(context, PopupVideoPlayer.class, queue, selectOnAppend, resumePlayback));
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_POPUP);
|
||||||
|
startService(context, intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) {
|
||||||
|
@ -159,8 +166,9 @@ public class NavigationHelper {
|
||||||
|
|
||||||
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, boolean selectOnAppend, final boolean resumePlayback) {
|
public static void enqueueOnBackgroundPlayer(final Context context, final PlayQueue queue, boolean selectOnAppend, final boolean resumePlayback) {
|
||||||
Toast.makeText(context, R.string.background_player_append, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.background_player_append, Toast.LENGTH_SHORT).show();
|
||||||
startService(context,
|
Intent intent = getPlayerEnqueueIntent(context, MainPlayer.class, queue, selectOnAppend, resumePlayback);
|
||||||
getPlayerEnqueueIntent(context, BackgroundPlayer.class, queue, selectOnAppend, resumePlayback));
|
intent.putExtra(VideoPlayer.PLAYER_TYPE, VideoPlayer.PLAYER_TYPE_AUDIO);
|
||||||
|
startService(context, intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startService(@NonNull final Context context, @NonNull final Intent intent) {
|
public static void startService(@NonNull final Context context, @NonNull final Intent intent) {
|
||||||
|
@ -281,29 +289,35 @@ public class NavigationHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title) {
|
public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title) {
|
||||||
openVideoDetailFragment(fragmentManager, serviceId, url, title, false);
|
openVideoDetailFragment(fragmentManager, serviceId, url, title, true, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title, boolean autoPlay) {
|
public static void openVideoDetailFragment(FragmentManager fragmentManager, int serviceId, String url, String title, boolean autoPlay, PlayQueue playQueue) {
|
||||||
Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_holder);
|
Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_player_holder);
|
||||||
if (title == null) title = "";
|
if (title == null) title = "";
|
||||||
|
|
||||||
if (fragment instanceof VideoDetailFragment && fragment.isVisible()) {
|
if (fragment instanceof VideoDetailFragment && fragment.isVisible()) {
|
||||||
|
expandMainPlayer(fragment.getActivity());
|
||||||
VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
|
VideoDetailFragment detailFragment = (VideoDetailFragment) fragment;
|
||||||
detailFragment.setAutoplay(autoPlay);
|
detailFragment.setAutoplay(autoPlay);
|
||||||
detailFragment.selectAndLoadVideo(serviceId, url, title);
|
detailFragment.selectAndLoadVideo(serviceId, url, title, playQueue);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoDetailFragment instance = VideoDetailFragment.getInstance(serviceId, url, title);
|
VideoDetailFragment instance = VideoDetailFragment.getInstance(serviceId, url, title, playQueue);
|
||||||
instance.setAutoplay(autoPlay);
|
instance.setAutoplay(autoPlay);
|
||||||
|
|
||||||
defaultTransaction(fragmentManager)
|
defaultTransaction(fragmentManager)
|
||||||
.replace(R.id.fragment_holder, instance)
|
.replace(R.id.fragment_player_holder, instance)
|
||||||
.addToBackStack(null)
|
.runOnCommit(() -> expandMainPlayer(instance.getActivity()))
|
||||||
.commit();
|
.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void expandMainPlayer(Context context) {
|
||||||
|
final Intent intent = new Intent(VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER);
|
||||||
|
context.sendBroadcast(intent);
|
||||||
|
}
|
||||||
|
|
||||||
public static void openChannelFragment(
|
public static void openChannelFragment(
|
||||||
FragmentManager fragmentManager,
|
FragmentManager fragmentManager,
|
||||||
int serviceId,
|
int serviceId,
|
||||||
|
@ -458,10 +472,6 @@ public class NavigationHelper {
|
||||||
return getServicePlayerActivityIntent(context, BackgroundPlayerActivity.class);
|
return getServicePlayerActivityIntent(context, BackgroundPlayerActivity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Intent getPopupPlayerActivityIntent(final Context context) {
|
|
||||||
return getServicePlayerActivityIntent(context, PopupVideoPlayerActivity.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Intent getServicePlayerActivityIntent(final Context context,
|
private static Intent getServicePlayerActivityIntent(final Context context,
|
||||||
final Class activityClass) {
|
final Class activityClass) {
|
||||||
Intent intent = new Intent(context, activityClass);
|
Intent intent = new Intent(context, activityClass);
|
||||||
|
|
|
@ -17,6 +17,6 @@ public class ShareUtils {
|
||||||
intent.setType("text/plain");
|
intent.setType("text/plain");
|
||||||
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, url);
|
intent.putExtra(Intent.EXTRA_TEXT, url);
|
||||||
context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_dialog_title)));
|
context.startActivity(Intent.createChooser(intent, context.getString(R.string.share_dialog_title)).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
android:background="@color/black"
|
||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||||
|
@ -49,9 +50,9 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/playQueuePanel"
|
android:id="@+id/playQueuePanel"
|
||||||
android:layout_width="380dp"
|
android:layout_width="380dp"
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_height="match_parent"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
android:background="?attr/queue_background_color"
|
android:background="?attr/queue_background_color"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
@ -120,7 +121,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_below="@id/playQueueControl"
|
android:layout_below="@id/playQueueControl"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layoutManager="LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:listitem="@layout/play_queue_item"/>
|
tools:listitem="@layout/play_queue_item"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -133,37 +134,46 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<!-- All top controls in this layout -->
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/playbackWindowRoot"
|
android:id="@+id/playbackWindowRoot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<RelativeLayout
|
<LinearLayout
|
||||||
android:id="@+id/topControls"
|
android:id="@+id/topControls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:background="@drawable/player_top_controls_bg"
|
android:background="@drawable/player_top_controls_bg"
|
||||||
|
android:orientation="vertical"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:paddingTop="10dp"
|
android:baselineAligned="false"
|
||||||
android:paddingBottom="10dp"
|
android:layout_toStartOf="@id/fullScreenButton">
|
||||||
android:paddingLeft="5dp"
|
|
||||||
android:paddingRight="5dp"
|
<LinearLayout
|
||||||
|
android:id="@+id/primaryControls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingLeft="2dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/metadataView"
|
android:id="@+id/metadataView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_toLeftOf="@+id/qualityTextView"
|
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="8dp"
|
android:paddingLeft="8dp"
|
||||||
android:paddingRight="8dp"
|
android:paddingRight="8dp"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/titleTextView"
|
android:id="@+id/titleTextView"
|
||||||
|
@ -204,13 +214,13 @@
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/playbackSpeed"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:text="720p"
|
android:text="720p"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:visibility="visible"
|
||||||
tools:ignore="HardcodedText,RtlHardcoded"/>
|
tools:ignore="HardcodedText,RtlHardcoded"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -218,7 +228,6 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/queueButton"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minHeight="35dp"
|
android:minHeight="35dp"
|
||||||
android:minWidth="40dp"
|
android:minWidth="40dp"
|
||||||
|
@ -226,7 +235,7 @@
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
tools:text="1x" />
|
tools:text="1x"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/queueButton"
|
android:id="@+id/queueButton"
|
||||||
|
@ -234,20 +243,19 @@
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/moreOptionsButton"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:src="@drawable/ic_list_white_24dp"
|
android:src="@drawable/ic_list_white_24dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/moreOptionsButton"
|
android:id="@+id/moreOptionsButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
@ -256,16 +264,18 @@
|
||||||
android:src="@drawable/ic_expand_more_white_24dp"
|
android:src="@drawable/ic_expand_more_white_24dp"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
android:id="@+id/secondaryControls"
|
android:id="@+id/secondaryControls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/topControls"
|
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:paddingLeft="5dp"
|
android:paddingTop="4dp"
|
||||||
android:paddingRight="5dp"
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingStart="6dp"
|
||||||
|
android:paddingEnd="6dp"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:ignore="RtlHardcoded"
|
tools:ignore="RtlHardcoded"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
@ -274,9 +284,7 @@
|
||||||
android:id="@+id/resizeTextView"
|
android:id="@+id/resizeTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="8dp"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
|
@ -291,18 +299,50 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="8dp"
|
||||||
android:layout_toLeftOf="@id/switchBackground"
|
|
||||||
android:layout_toRightOf="@id/resizeTextView"
|
|
||||||
android:gravity="center|left"
|
android:gravity="center|left"
|
||||||
android:minHeight="35dp"
|
android:minHeight="35dp"
|
||||||
android:minWidth="40dp"
|
android:minWidth="50dp"
|
||||||
android:paddingLeft="2dp"
|
|
||||||
android:paddingRight="2dp"
|
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||||
tools:text="English" />
|
tools:text="English"/>
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:id="@+id/spaceBeforeButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="3"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playWithKodi"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_channel_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/play_with_kodi_title"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/openInBrowser"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_language_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/open_in_browser"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/share"
|
android:id="@+id/share"
|
||||||
|
@ -310,8 +350,6 @@
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_marginLeft="4dp"
|
android:layout_marginLeft="4dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
|
@ -321,56 +359,25 @@
|
||||||
android:contentDescription="@string/share"
|
android:contentDescription="@string/share"
|
||||||
tools:ignore="RtlHardcoded"/>
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
<ImageButton
|
</LinearLayout>
|
||||||
android:id="@+id/toggleOrientation"
|
|
||||||
android:layout_width="30dp"
|
</LinearLayout>
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_marginLeft="4dp"
|
|
||||||
android:layout_marginRight="4dp"
|
|
||||||
android:layout_toLeftOf="@id/share"
|
|
||||||
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
|
<ImageButton
|
||||||
android:id="@+id/switchPopup"
|
android:id="@+id/fullScreenButton"
|
||||||
android:layout_width="30dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginLeft="4dp"
|
|
||||||
android:layout_marginRight="4dp"
|
android:layout_marginRight="4dp"
|
||||||
android:layout_toLeftOf="@id/toggleOrientation"
|
android:padding="4dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_alignParentRight="true"
|
||||||
|
android:background="@drawable/player_top_controls_bg"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/ic_fullscreen_exit_white"
|
android:src="@drawable/ic_fullscreen_white"
|
||||||
android:background="?attr/selectableItemBackground"
|
tools:ignore="ContentDescription,RtlHardcoded"
|
||||||
android:contentDescription="@string/switch_to_popup"
|
android:visibility="gone"
|
||||||
tools:ignore="RtlHardcoded"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/switchBackground"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_marginLeft="4dp"
|
|
||||||
android:layout_marginRight="4dp"
|
|
||||||
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
|
<LinearLayout
|
||||||
android:id="@+id/bottomControls"
|
android:id="@+id/bottomControls"
|
||||||
|
@ -380,6 +387,7 @@
|
||||||
android:background="@drawable/player_controls_bg"
|
android:background="@drawable/player_controls_bg"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
|
android:paddingBottom="2dp"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
|
@ -388,7 +396,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minHeight="40dp"
|
android:minHeight="30dp"
|
||||||
android:text="-:--:--"
|
android:text="-:--:--"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
tools:ignore="HardcodedText"
|
tools:ignore="HardcodedText"
|
||||||
|
@ -433,65 +441,52 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="5.5">
|
||||||
|
<!--tools:visibility="gone">-->
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/playPauseButton"
|
android:id="@+id/playPreviousButton"
|
||||||
android:layout_width="100dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
android:layout_centerInParent="true"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/exo_controls_previous"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playPauseButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/ic_pause_white"
|
android:src="@drawable/ic_pause_white"
|
||||||
tools:ignore="ContentDescription"/>
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/playPreviousButton"
|
|
||||||
android:layout_width="50dp"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:layout_marginRight="30dp"
|
|
||||||
android:layout_marginEnd="30dp"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_toLeftOf="@id/playPauseButton"
|
|
||||||
android:layout_toStartOf="@id/playPauseButton"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:scaleType="fitXY"
|
|
||||||
android:src="@drawable/exo_controls_previous"
|
|
||||||
tools:ignore="ContentDescription"/>
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/playNextButton"
|
android:id="@+id/playNextButton"
|
||||||
android:layout_width="50dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="100dp"
|
||||||
android:layout_marginLeft="30dp"
|
android:layout_weight="1"
|
||||||
android:layout_marginStart="30dp"
|
android:layout_marginStart="30dp"
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_toRightOf="@id/playPauseButton"
|
|
||||||
android:layout_toEndOf="@id/playPauseButton"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/exo_controls_next"
|
android:src="@drawable/exo_controls_next"
|
||||||
tools:ignore="ContentDescription"/>
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
<Button
|
</LinearLayout>
|
||||||
android:id="@+id/closeButton"
|
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/playPauseButton"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:text="@string/close"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:visibility="invisible" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
@ -533,10 +528,7 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_toEndOf="@+id/loading_panel"
|
|
||||||
android:layout_toRightOf="@+id/loading_panel"
|
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
@ -611,4 +603,42 @@
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/resizing_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|top"
|
||||||
|
android:background="#6e000000"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:text="@string/popup_resizing_indicator_title"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/closingOverlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#AAFF0000"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/closeButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:text="@string/close"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/windowBackground">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
android:id="@+id/video_item_detail"
|
android:id="@+id/video_item_detail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -17,6 +22,30 @@
|
||||||
android:layout_weight="5"
|
android:layout_weight="5"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<androidx.viewpager.widget.ViewPager
|
||||||
|
android:id="@+id/viewpager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/tablayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="bottom|center"
|
||||||
|
app:tabBackground="@drawable/tab_selector"
|
||||||
|
app:tabGravity="center"
|
||||||
|
app:tabIndicatorHeight="0dp"/>
|
||||||
|
|
||||||
|
</androidx.viewpager.widget.ViewPager>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbarlayout"
|
android:id="@+id/appbarlayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -144,6 +173,13 @@
|
||||||
tools:progress="40"
|
tools:progress="40"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<!-- Player will be inserted here in realtime -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_placeholder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
|
@ -153,7 +189,6 @@
|
||||||
android:id="@+id/detail_content_root_layout"
|
android:id="@+id/detail_content_root_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:windowBackground"
|
|
||||||
app:layout_scrollFlags="scroll">
|
app:layout_scrollFlags="scroll">
|
||||||
|
|
||||||
<!-- TITLE -->
|
<!-- TITLE -->
|
||||||
|
@ -506,26 +541,6 @@
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.viewpager.widget.ViewPager
|
|
||||||
android:id="@+id/viewpager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
|
||||||
android:id="@+id/tablayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|center"
|
|
||||||
android:background="@color/transparent_background_color"
|
|
||||||
app:tabBackground="@drawable/tab_selector"
|
|
||||||
app:tabGravity="center"
|
|
||||||
app:tabIndicatorHeight="0dp">
|
|
||||||
|
|
||||||
</com.google.android.material.tabs.TabLayout>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -537,3 +552,105 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/overlay_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:alpha="0"
|
||||||
|
tools:alpha="1"
|
||||||
|
android:paddingLeft="@dimen/video_item_search_padding"
|
||||||
|
android:paddingRight="@dimen/video_item_search_padding"
|
||||||
|
android:background="?attr/windowBackground" >
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/overlay_thumbnail"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:contentDescription="@string/list_thumbnail_view_description"
|
||||||
|
android:src="@drawable/dummy_thumbnail"
|
||||||
|
android:background="@color/transparent_background_color"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/overlay_metadata_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@dimen/video_item_search_padding"
|
||||||
|
android:paddingRight="@dimen/video_item_search_padding"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:layout_toEndOf="@+id/overlay_thumbnail"
|
||||||
|
android:layout_toStartOf="@+id/overlay_buttons_layout"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/overlay_title_text_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="@dimen/video_item_search_title_text_size"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="The Video Title LONG very LONVideo Title LONG very LONG"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/overlay_channel_text_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textSize="@dimen/video_item_search_uploader_text_size"
|
||||||
|
tools:text="The Video Artist LONG very LONG very Long"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/overlay_buttons_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="@dimen/video_item_search_padding"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/overlay_play_pause_button"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_pause_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/overlay_close_button"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="?attr/close"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -2,6 +2,7 @@
|
||||||
<androidx.drawerlayout.widget.DrawerLayout
|
<androidx.drawerlayout.widget.DrawerLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/drawer_layout"
|
android:id="@+id/drawer_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
@ -22,6 +23,23 @@
|
||||||
<include layout="@layout/toolbar_layout" />
|
<include layout="@layout/toolbar_layout" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fragment_player_holder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
app:behavior_hideable="true"
|
||||||
|
app:behavior_peekHeight="0dp"
|
||||||
|
app:layout_behavior="org.schabi.newpipe.player.event.CustomBottomSheetBehavior">
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
|
||||||
<include layout="@layout/drawer_layout"/>
|
<include layout="@layout/drawer_layout"/>
|
||||||
|
|
||||||
</androidx.drawerlayout.widget.DrawerLayout>
|
</androidx.drawerlayout.widget.DrawerLayout>
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
android:background="@color/black"
|
||||||
android:gravity="center">
|
android:gravity="center">
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
<com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||||
|
@ -118,7 +119,7 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_below="@id/playQueueControl"
|
android:layout_below="@id/playQueueControl"
|
||||||
android:scrollbars="vertical"
|
android:scrollbars="vertical"
|
||||||
app:layoutManager="LinearLayoutManager"
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
tools:listitem="@layout/play_queue_item"/>
|
tools:listitem="@layout/play_queue_item"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
@ -131,37 +132,46 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
|
<!-- All top controls in this layout -->
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:id="@+id/playbackWindowRoot"
|
android:id="@+id/playbackWindowRoot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<RelativeLayout
|
<LinearLayout
|
||||||
android:id="@+id/topControls"
|
android:id="@+id/topControls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:background="@drawable/player_top_controls_bg"
|
android:background="@drawable/player_top_controls_bg"
|
||||||
|
android:orientation="vertical"
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:paddingTop="10dp"
|
android:baselineAligned="false"
|
||||||
android:paddingBottom="10dp"
|
android:layout_toStartOf="@id/fullScreenButton">
|
||||||
android:paddingLeft="5dp"
|
|
||||||
android:paddingRight="5dp"
|
<LinearLayout
|
||||||
|
android:id="@+id/primaryControls"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:baselineAligned="false"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingTop="4dp"
|
||||||
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingLeft="2dp"
|
||||||
|
android:paddingRight="6dp"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/metadataView"
|
android:id="@+id/metadataView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_toLeftOf="@+id/qualityTextView"
|
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingLeft="8dp"
|
android:paddingLeft="8dp"
|
||||||
android:paddingRight="8dp"
|
android:paddingRight="8dp"
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/titleTextView"
|
android:id="@+id/titleTextView"
|
||||||
|
@ -202,13 +212,13 @@
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/playbackSpeed"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:text="720p"
|
android:text="720p"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:visibility="visible"
|
||||||
tools:ignore="HardcodedText,RtlHardcoded"/>
|
tools:ignore="HardcodedText,RtlHardcoded"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -216,7 +226,6 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/queueButton"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minHeight="35dp"
|
android:minHeight="35dp"
|
||||||
android:minWidth="40dp"
|
android:minWidth="40dp"
|
||||||
|
@ -224,7 +233,7 @@
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
tools:text="1x" />
|
tools:text="1x"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/queueButton"
|
android:id="@+id/queueButton"
|
||||||
|
@ -232,20 +241,19 @@
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_toLeftOf="@+id/moreOptionsButton"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:src="@drawable/ic_list_white_24dp"
|
android:src="@drawable/ic_list_white_24dp"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/moreOptionsButton"
|
android:id="@+id/moreOptionsButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_marginLeft="2dp"
|
android:layout_marginLeft="2dp"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
@ -254,16 +262,18 @@
|
||||||
android:src="@drawable/ic_expand_more_white_24dp"
|
android:src="@drawable/ic_expand_more_white_24dp"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
android:id="@+id/secondaryControls"
|
android:id="@+id/secondaryControls"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/topControls"
|
|
||||||
android:gravity="top"
|
android:gravity="top"
|
||||||
android:paddingLeft="5dp"
|
android:paddingTop="4dp"
|
||||||
android:paddingRight="5dp"
|
android:paddingBottom="7dp"
|
||||||
|
android:paddingStart="6dp"
|
||||||
|
android:paddingEnd="6dp"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
tools:ignore="RtlHardcoded"
|
tools:ignore="RtlHardcoded"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
@ -272,9 +282,7 @@
|
||||||
android:id="@+id/resizeTextView"
|
android:id="@+id/resizeTextView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="35dp"
|
android:layout_height="35dp"
|
||||||
android:layout_marginLeft="8dp"
|
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="8dp"
|
||||||
android:layout_alignParentLeft="true"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minWidth="50dp"
|
android:minWidth="50dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
|
@ -289,18 +297,50 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="8dp"
|
android:layout_marginLeft="8dp"
|
||||||
android:layout_marginRight="8dp"
|
android:layout_marginRight="8dp"
|
||||||
android:layout_toLeftOf="@id/switchBackground"
|
|
||||||
android:layout_toRightOf="@id/resizeTextView"
|
|
||||||
android:gravity="center|left"
|
android:gravity="center|left"
|
||||||
android:minHeight="35dp"
|
android:minHeight="35dp"
|
||||||
android:minWidth="40dp"
|
android:minWidth="50dp"
|
||||||
android:paddingLeft="2dp"
|
|
||||||
android:paddingRight="2dp"
|
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
android:background="?attr/selectableItemBackground"
|
android:background="?attr/selectableItemBackground"
|
||||||
tools:ignore="RelativeOverlap,RtlHardcoded"
|
tools:ignore="RelativeOverlap,RtlHardcoded"
|
||||||
tools:text="English" />
|
tools:text="English"/>
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:id="@+id/spaceBeforeButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="3"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playWithKodi"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_channel_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/play_with_kodi_title"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/openInBrowser"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_marginLeft="4dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:scaleType="fitXY"
|
||||||
|
android:src="@drawable/ic_language_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:contentDescription="@string/open_in_browser"
|
||||||
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/share"
|
android:id="@+id/share"
|
||||||
|
@ -308,8 +348,6 @@
|
||||||
android:layout_height="30dp"
|
android:layout_height="30dp"
|
||||||
android:layout_marginLeft="4dp"
|
android:layout_marginLeft="4dp"
|
||||||
android:layout_marginRight="2dp"
|
android:layout_marginRight="2dp"
|
||||||
android:layout_alignParentRight="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
|
@ -319,56 +357,25 @@
|
||||||
android:contentDescription="@string/share"
|
android:contentDescription="@string/share"
|
||||||
tools:ignore="RtlHardcoded"/>
|
tools:ignore="RtlHardcoded"/>
|
||||||
|
|
||||||
<ImageButton
|
</LinearLayout>
|
||||||
android:id="@+id/toggleOrientation"
|
|
||||||
android:layout_width="30dp"
|
</LinearLayout>
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_marginLeft="4dp"
|
|
||||||
android:layout_marginRight="4dp"
|
|
||||||
android:layout_toLeftOf="@id/share"
|
|
||||||
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
|
<ImageButton
|
||||||
android:id="@+id/switchPopup"
|
android:id="@+id/fullScreenButton"
|
||||||
android:layout_width="30dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="30dp"
|
android:layout_height="40dp"
|
||||||
android:layout_marginLeft="4dp"
|
|
||||||
android:layout_marginRight="4dp"
|
android:layout_marginRight="4dp"
|
||||||
android:layout_toLeftOf="@id/toggleOrientation"
|
android:padding="4dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_alignParentRight="true"
|
||||||
|
android:background="@drawable/player_top_controls_bg"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/ic_fullscreen_exit_white"
|
android:src="@drawable/ic_fullscreen_white"
|
||||||
android:background="?attr/selectableItemBackground"
|
tools:ignore="ContentDescription,RtlHardcoded"
|
||||||
android:contentDescription="@string/switch_to_popup"
|
android:visibility="gone"
|
||||||
tools:ignore="RtlHardcoded"/>
|
tools:visibility="visible"/>
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/switchBackground"
|
|
||||||
android:layout_width="30dp"
|
|
||||||
android:layout_height="30dp"
|
|
||||||
android:layout_marginLeft="4dp"
|
|
||||||
android:layout_marginRight="4dp"
|
|
||||||
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
|
<LinearLayout
|
||||||
android:id="@+id/bottomControls"
|
android:id="@+id/bottomControls"
|
||||||
|
@ -378,6 +385,7 @@
|
||||||
android:background="@drawable/player_controls_bg"
|
android:background="@drawable/player_controls_bg"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
|
android:paddingBottom="2dp"
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
|
@ -386,7 +394,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minHeight="40dp"
|
android:minHeight="30dp"
|
||||||
android:text="-:--:--"
|
android:text="-:--:--"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
tools:ignore="HardcodedText"
|
tools:ignore="HardcodedText"
|
||||||
|
@ -431,65 +439,52 @@
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:weightSum="5.5">
|
||||||
|
<!--tools:visibility="gone">-->
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/playPauseButton"
|
android:id="@+id/playPreviousButton"
|
||||||
android:layout_width="100dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="100dp"
|
||||||
android:layout_centerInParent="true"
|
android:layout_weight="1"
|
||||||
|
android:layout_marginEnd="30dp"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitCenter"
|
||||||
|
android:src="@drawable/exo_controls_previous"
|
||||||
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/playPauseButton"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="100dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/ic_pause_white"
|
android:src="@drawable/ic_pause_white"
|
||||||
tools:ignore="ContentDescription"/>
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/playPreviousButton"
|
|
||||||
android:layout_width="50dp"
|
|
||||||
android:layout_height="50dp"
|
|
||||||
android:layout_marginRight="30dp"
|
|
||||||
android:layout_marginEnd="30dp"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_toLeftOf="@id/playPauseButton"
|
|
||||||
android:layout_toStartOf="@id/playPauseButton"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:scaleType="fitXY"
|
|
||||||
android:src="@drawable/exo_controls_previous"
|
|
||||||
tools:ignore="ContentDescription"/>
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/playNextButton"
|
android:id="@+id/playNextButton"
|
||||||
android:layout_width="50dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="50dp"
|
android:layout_height="100dp"
|
||||||
android:layout_marginLeft="30dp"
|
android:layout_weight="1"
|
||||||
android:layout_marginStart="30dp"
|
android:layout_marginStart="30dp"
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_toRightOf="@id/playPauseButton"
|
|
||||||
android:layout_toEndOf="@id/playPauseButton"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitCenter"
|
||||||
android:src="@drawable/exo_controls_next"
|
android:src="@drawable/exo_controls_next"
|
||||||
tools:ignore="ContentDescription"/>
|
tools:ignore="ContentDescription"/>
|
||||||
|
|
||||||
<Button
|
</LinearLayout>
|
||||||
android:id="@+id/closeButton"
|
|
||||||
style="@style/Widget.AppCompat.Button.Borderless"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_below="@id/playPauseButton"
|
|
||||||
android:layout_centerInParent="true"
|
|
||||||
android:layout_marginTop="10dp"
|
|
||||||
android:background="?attr/selectableItemBackgroundBorderless"
|
|
||||||
android:clickable="true"
|
|
||||||
android:focusable="true"
|
|
||||||
android:text="@string/close"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:visibility="invisible" />
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
@ -531,10 +526,7 @@
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_toEndOf="@+id/loading_panel"
|
|
||||||
android:layout_toRightOf="@+id/loading_panel"
|
|
||||||
tools:ignore="RtlHardcoded">
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
|
@ -609,4 +601,42 @@
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/resizing_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="left|top"
|
||||||
|
android:background="#6e000000"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="5dp"
|
||||||
|
android:text="@string/popup_resizing_indicator_title"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/closingOverlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="#AAFF0000"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/closeButton"
|
||||||
|
style="@style/Widget.AppCompat.Button.Borderless"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:text="@string/close"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -5,13 +5,44 @@
|
||||||
android:id="@+id/video_item_detail"
|
android:id="@+id/video_item_detail"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/windowBackground"
|
||||||
android:focusableInTouchMode="true">
|
android:focusableInTouchMode="true">
|
||||||
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:id="@+id/detail_main_content"
|
android:id="@+id/detail_main_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content">
|
||||||
android:fitsSystemWindows="true">
|
|
||||||
|
<!--
|
||||||
|
You may wonder why this NestedScrollView locates on top of the file. That's because BottomSheetBehavior
|
||||||
|
can work well only with one element that implements nested scrolling. But we have two:
|
||||||
|
one NestedScrollView for ViewPager with id = viewpager here
|
||||||
|
second ViewPager with id = playQueue inside activity_main_player.xml.
|
||||||
|
By placing this NestedScrollView on top of the file we are getting this ViewPager working -->
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<androidx.viewpager.widget.ViewPager
|
||||||
|
android:id="@+id/viewpager"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" >
|
||||||
|
|
||||||
|
<com.google.android.material.tabs.TabLayout
|
||||||
|
android:id="@+id/tablayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_gravity="bottom|center"
|
||||||
|
app:tabBackground="@drawable/tab_selector"
|
||||||
|
app:tabGravity="center"
|
||||||
|
app:tabIndicatorHeight="0dp"/>
|
||||||
|
|
||||||
|
</androidx.viewpager.widget.ViewPager>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbarlayout"
|
android:id="@+id/appbarlayout"
|
||||||
|
@ -140,6 +171,13 @@
|
||||||
tools:progress="40"
|
tools:progress="40"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<!-- Player will be inserted here in realtime -->
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/player_placeholder"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
/>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||||
|
@ -149,7 +187,6 @@
|
||||||
android:id="@+id/detail_content_root_layout"
|
android:id="@+id/detail_content_root_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:windowBackground"
|
|
||||||
app:layout_scrollFlags="scroll">
|
app:layout_scrollFlags="scroll">
|
||||||
|
|
||||||
<!-- TITLE -->
|
<!-- TITLE -->
|
||||||
|
@ -504,25 +541,106 @@
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
|
||||||
<androidx.viewpager.widget.ViewPager
|
|
||||||
android:id="@+id/viewpager"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
|
||||||
android:id="@+id/tablayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|center"
|
|
||||||
android:background="@color/transparent_background_color"
|
|
||||||
app:tabBackground="@drawable/tab_selector"
|
|
||||||
app:tabGravity="center"
|
|
||||||
app:tabIndicatorHeight="0dp">
|
|
||||||
|
|
||||||
</com.google.android.material.tabs.TabLayout>
|
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/overlay_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:alpha="0"
|
||||||
|
tools:alpha="1"
|
||||||
|
android:paddingLeft="@dimen/video_item_search_padding"
|
||||||
|
android:paddingRight="@dimen/video_item_search_padding"
|
||||||
|
android:background="?attr/windowBackground" >
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/overlay_thumbnail"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:contentDescription="@string/list_thumbnail_view_description"
|
||||||
|
android:src="@drawable/dummy_thumbnail"
|
||||||
|
android:background="@color/transparent_background_color"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/overlay_metadata_layout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="@dimen/video_item_search_padding"
|
||||||
|
android:paddingRight="@dimen/video_item_search_padding"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:layout_toEndOf="@+id/overlay_thumbnail"
|
||||||
|
android:layout_toStartOf="@+id/overlay_buttons_layout"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/overlay_title_text_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
|
android:textSize="@dimen/video_item_search_title_text_size"
|
||||||
|
tools:ignore="RtlHardcoded"
|
||||||
|
tools:text="The Video Title LONG very LONVideo Title LONG very LONG"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/overlay_channel_text_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:fadingEdge="horizontal"
|
||||||
|
android:marqueeRepeatLimit="marquee_forever"
|
||||||
|
android:scrollHorizontally="true"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:textSize="@dimen/video_item_search_uploader_text_size"
|
||||||
|
tools:text="The Video Artist LONG very LONG very Long"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/overlay_buttons_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="60dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingLeft="@dimen/video_item_search_padding"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
tools:ignore="RtlHardcoded">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/overlay_play_pause_button"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:layout_marginRight="2dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_pause_white_24dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/overlay_close_button"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginLeft="2dp"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="?attr/close"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
|
@ -7,4 +7,9 @@
|
||||||
android:orderInCategory="1999"
|
android:orderInCategory="1999"
|
||||||
android:title="@string/switch_to_popup"
|
android:title="@string/switch_to_popup"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
|
<item android:id="@+id/action_switch_background"
|
||||||
|
android:orderInCategory="999"
|
||||||
|
android:title="@string/switch_to_background"
|
||||||
|
app:showAsAction="never"/>
|
||||||
</menu>
|
</menu>
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
<dimen name="video_item_detail_like_image_height">18sp</dimen>
|
<dimen name="video_item_detail_like_image_height">18sp</dimen>
|
||||||
<dimen name="video_item_detail_like_image_width">18sp</dimen>
|
<dimen name="video_item_detail_like_image_width">18sp</dimen>
|
||||||
<dimen name="channel_avatar_size">70dp</dimen>
|
<dimen name="channel_avatar_size">70dp</dimen>
|
||||||
|
<dimen name="mini_player_height">60dp</dimen>
|
||||||
<!-- Paddings & Margins -->
|
<!-- Paddings & Margins -->
|
||||||
<dimen name="video_item_detail_like_margin">5dp</dimen>
|
<dimen name="video_item_detail_like_margin">5dp</dimen>
|
||||||
<dimen name="video_item_detail_error_panel_margin">50dp</dimen>
|
<dimen name="video_item_detail_error_panel_margin">50dp</dimen>
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:dependency="@string/enable_playback_resume_key"
|
|
||||||
android:key="@string/enable_playback_state_lists_key"
|
android:key="@string/enable_playback_state_lists_key"
|
||||||
android:summary="@string/enable_playback_state_lists_summary"
|
android:summary="@string/enable_playback_state_lists_summary"
|
||||||
android:title="@string/enable_playback_state_lists_title"
|
android:title="@string/enable_playback_state_lists_title"
|
||||||
|
|
Loading…
Reference in a new issue