Merge remote-tracking branch 'origin/dev' into dev
|
@ -8,8 +8,8 @@ android {
|
|||
applicationId "org.schabi.newpipe"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 27
|
||||
versionCode 45
|
||||
versionName "0.11.4"
|
||||
versionCode 46
|
||||
versionName "0.11.5"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
@ -55,7 +55,7 @@ dependencies {
|
|||
exclude module: 'support-annotations'
|
||||
}
|
||||
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:9de63f8c0a170a066'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:1c97da8b51b3610'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:1.10.19'
|
||||
|
|
|
@ -28,8 +28,13 @@ import android.os.Looper;
|
|||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
|
@ -45,6 +50,7 @@ import org.schabi.newpipe.database.history.dao.WatchHistoryDAO;
|
|||
import org.schabi.newpipe.database.history.model.HistoryEntry;
|
||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
||||
import org.schabi.newpipe.database.history.model.WatchHistoryEntry;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
|
@ -69,6 +75,7 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
|
|||
private static final String TAG = "MainActivity";
|
||||
public static final boolean DEBUG = false;
|
||||
private SharedPreferences sharedPreferences;
|
||||
private ActionBarDrawerToggle toggle = null;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Activity's LifeCycle
|
||||
|
@ -76,7 +83,8 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
|
|||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
||||
ThemeHelper.setTheme(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
|
@ -85,8 +93,59 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
|
|||
initFragments();
|
||||
}
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
final DrawerLayout drawer = findViewById(R.id.drawer_layout);
|
||||
final NavigationView drawerItems = findViewById(R.id.navigation);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
drawerItems.getMenu().getItem(NewPipe.getIdOfService(PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("service", "YouTube"))).setChecked(true);
|
||||
|
||||
if (!BuildConfig.BUILD_TYPE.equals("release")) {
|
||||
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.drawer_open, R.string.drawer_close);
|
||||
toggle.syncState();
|
||||
drawer.addDrawerListener(toggle);
|
||||
|
||||
drawerItems.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
drawerItems.getMenu().getItem(NewPipe.getIdOfService(PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("service", "YouTube"))).setChecked(false);
|
||||
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit();
|
||||
editor.putString("service", item.getTitle().toString());
|
||||
editor.apply();
|
||||
drawer.closeDrawers();
|
||||
drawerItems.getMenu().getItem(NewPipe.getIdOfService(PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString("service", "YouTube"))).setChecked(true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||
}
|
||||
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
|
||||
@Override
|
||||
public void onBackStackChanged() {
|
||||
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onBackPressed();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
if (toggle != null) {
|
||||
toggle.syncState();
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
drawer.openDrawer(GravityCompat.START);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
initHistory();
|
||||
|
|
|
@ -138,7 +138,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_search:
|
||||
NavigationHelper.openSearchFragment(getFragmentManager(), 0, "");
|
||||
NavigationHelper.openSearchFragment(getFragmentManager(), NewPipe.getIdOfService(PreferenceManager.getDefaultSharedPreferences(getActivity()).getString("service", "YouTube")), "");
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
|
|
@ -342,7 +342,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
|
|||
}
|
||||
break;
|
||||
case R.id.detail_thumbnail_root_layout:
|
||||
if (currentInfo.video_streams.isEmpty() && currentInfo.video_only_streams.isEmpty()) {
|
||||
openBackgroundPlayer(false);
|
||||
} else {
|
||||
openVideoPlayer();
|
||||
}
|
||||
break;
|
||||
case R.id.detail_title_root_layout:
|
||||
toggleTitleAndDescription();
|
||||
|
@ -1158,6 +1162,13 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
|
|||
showSnackBarError(info.getErrors(), UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(info.getServiceId()), info.getUrl(), 0);
|
||||
}
|
||||
|
||||
if (info.video_streams.isEmpty() && info.video_only_streams.isEmpty()) {
|
||||
detailControlsBackground.setVisibility(View.GONE);
|
||||
detailControlsPopup.setVisibility(View.GONE);
|
||||
spinnerToolbar.setVisibility(View.GONE);
|
||||
thumbnailPlayButton.setImageResource(R.drawable.ic_headset_white_24dp);
|
||||
}
|
||||
|
||||
if (autoPlayEnabled) {
|
||||
openVideoPlayer();
|
||||
// Only auto play in the first open
|
||||
|
|
|
@ -124,20 +124,12 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
|
|||
currentWorker = loadResult(forceLoad)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<I>() {
|
||||
@Override
|
||||
public void accept(@NonNull I result) throws Exception {
|
||||
.subscribe((@NonNull I result) -> {
|
||||
isLoading.set(false);
|
||||
currentInfo = result;
|
||||
currentNextItemsUrl = result.next_streams_url;
|
||||
handleResult(result);
|
||||
}
|
||||
}, new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(@NonNull Throwable throwable) throws Exception {
|
||||
onError(throwable);
|
||||
}
|
||||
});
|
||||
}, (@NonNull Throwable throwable) -> onError(throwable));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,18 +145,12 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
|
|||
currentWorker = loadMoreItemsLogic()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<ListExtractor.NextItemsResult>() {
|
||||
@Override
|
||||
public void accept(@io.reactivex.annotations.NonNull ListExtractor.NextItemsResult nextItemsResult) throws Exception {
|
||||
.subscribe((@io.reactivex.annotations.NonNull ListExtractor.NextItemsResult nextItemsResult) -> {
|
||||
isLoading.set(false);
|
||||
handleNextItems(nextItemsResult);
|
||||
}
|
||||
}, new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
|
||||
}, (@io.reactivex.annotations.NonNull Throwable throwable) -> {
|
||||
isLoading.set(false);
|
||||
onError(throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
|
@ -37,7 +38,6 @@ import android.support.v7.widget.RecyclerView;
|
|||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
@ -62,6 +62,7 @@ import org.schabi.newpipe.util.AnimationUtils;
|
|||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
import org.schabi.newpipe.util.PopupMenuIconHacker;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -326,7 +327,7 @@ public final class MainVideoPlayer extends Activity {
|
|||
this.playNextButton = rootView.findViewById(R.id.playNextButton);
|
||||
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
|
||||
this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton);
|
||||
this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions, moreOptionsPopupMenu.getMenu());
|
||||
buildMoreOptionsMenu();
|
||||
|
||||
titleTextView.setSelected(true);
|
||||
channelTextView.setSelected(true);
|
||||
|
@ -379,7 +380,7 @@ public final class MainVideoPlayer extends Activity {
|
|||
titleTextView.setText(getVideoTitle());
|
||||
channelTextView.setText(getUploaderName());
|
||||
|
||||
playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
||||
//playPauseButton.setImageResource(R.drawable.ic_pause_white);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -499,25 +500,7 @@ public final class MainVideoPlayer extends Activity {
|
|||
|
||||
private void onMoreOptionsClicked() {
|
||||
if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called");
|
||||
buildMoreOptionsMenu();
|
||||
|
||||
try {
|
||||
Field[] fields = moreOptionsPopupMenu.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if ("mPopup".equals(field.getName())) {
|
||||
field.setAccessible(true);
|
||||
Object menuPopupHelper = field.get(moreOptionsPopupMenu);
|
||||
Class<?> classPopupHelper = Class.forName(menuPopupHelper
|
||||
.getClass().getName());
|
||||
Method setForceIcons = classPopupHelper.getMethod(
|
||||
"setForceShowIcon", boolean.class);
|
||||
setForceIcons.invoke(menuPopupHelper, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
moreOptionsPopupMenu.show();
|
||||
isSomePopupMenuVisible = true;
|
||||
showControls(300);
|
||||
|
@ -659,7 +642,9 @@ public final class MainVideoPlayer extends Activity {
|
|||
}
|
||||
|
||||
private void buildMoreOptionsMenu() {
|
||||
if (moreOptionsPopupMenu == null) return;
|
||||
this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions,
|
||||
moreOptionsPopupMenu.getMenu());
|
||||
|
||||
moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.toggleOrientation:
|
||||
|
@ -674,6 +659,22 @@ public final class MainVideoPlayer extends Activity {
|
|||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
try {
|
||||
PopupMenuIconHacker.setShowPopupIcon(moreOptionsPopupMenu);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// fix icon theme
|
||||
if(ThemeHelper.isLightThemeSelected(MainVideoPlayer.this)) {
|
||||
moreOptionsPopupMenu.getMenu()
|
||||
.findItem(R.id.toggleOrientation)
|
||||
.setIcon(R.drawable.ic_screen_rotation_black_24dp);
|
||||
moreOptionsPopupMenu.getMenu()
|
||||
.findItem(R.id.switchPopup)
|
||||
.setIcon(R.drawable.ic_fullscreen_exit_black_24dp);
|
||||
}
|
||||
}
|
||||
|
||||
private void buildQueue() {
|
||||
|
|
|
@ -57,105 +57,96 @@ public final class ExtractorHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public static Single<SearchResult> searchFor(final int serviceId, final String query, final int pageNumber, final String contentCountry, final SearchEngine.Filter filter) {
|
||||
public static Single<SearchResult> searchFor(final int serviceId,
|
||||
final String query,
|
||||
final int pageNumber,
|
||||
final String contentCountry,
|
||||
final SearchEngine.Filter filter) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(new Callable<SearchResult>() {
|
||||
@Override
|
||||
public SearchResult call() throws Exception {
|
||||
return SearchResult.getSearchResult(NewPipe.getService(serviceId).getSearchEngine(),
|
||||
query, pageNumber, contentCountry, filter);
|
||||
}
|
||||
});
|
||||
return Single.fromCallable(() ->
|
||||
SearchResult.getSearchResult(NewPipe.getService(serviceId).getSearchEngine(),
|
||||
query, pageNumber, contentCountry, filter)
|
||||
);
|
||||
}
|
||||
|
||||
public static Single<NextItemsResult> getMoreSearchItems(final int serviceId, final String query, final int nextPageNumber, final String searchLanguage, final SearchEngine.Filter filter) {
|
||||
public static Single<NextItemsResult> getMoreSearchItems(final int serviceId,
|
||||
final String query,
|
||||
final int nextPageNumber,
|
||||
final String searchLanguage,
|
||||
final SearchEngine.Filter filter) {
|
||||
checkServiceId(serviceId);
|
||||
return searchFor(serviceId, query, nextPageNumber, searchLanguage, filter)
|
||||
.map(new Function<SearchResult, NextItemsResult>() {
|
||||
@Override
|
||||
public NextItemsResult apply(@NonNull SearchResult searchResult) throws Exception {
|
||||
return new NextItemsResult(searchResult.resultList, nextPageNumber + "", searchResult.errors);
|
||||
}
|
||||
});
|
||||
.map((@NonNull SearchResult searchResult) ->
|
||||
new NextItemsResult(searchResult.resultList,
|
||||
nextPageNumber + "",
|
||||
searchResult.errors));
|
||||
}
|
||||
|
||||
public static Single<List<String>> suggestionsFor(final int serviceId, final String query, final String contentCountry) {
|
||||
public static Single<List<String>> suggestionsFor(final int serviceId,
|
||||
final String query,
|
||||
final String contentCountry) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(new Callable<List<String>>() {
|
||||
@Override
|
||||
public List<String> call() throws Exception {
|
||||
return NewPipe.getService(serviceId).getSuggestionExtractor().suggestionList(query, contentCountry);
|
||||
}
|
||||
});
|
||||
return Single.fromCallable(() ->
|
||||
NewPipe.getService(serviceId)
|
||||
.getSuggestionExtractor()
|
||||
.suggestionList(query, contentCountry));
|
||||
}
|
||||
|
||||
public static Single<StreamInfo> getStreamInfo(final int serviceId, final String url, boolean forceLoad) {
|
||||
public static Single<StreamInfo> getStreamInfo(final int serviceId,
|
||||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<StreamInfo>() {
|
||||
@Override
|
||||
public StreamInfo call() throws Exception {
|
||||
return StreamInfo.getInfo(NewPipe.getService(serviceId), url);
|
||||
}
|
||||
}));
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
StreamInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
public static Single<ChannelInfo> getChannelInfo(final int serviceId, final String url, boolean forceLoad) {
|
||||
public static Single<ChannelInfo> getChannelInfo(final int serviceId,
|
||||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<ChannelInfo>() {
|
||||
@Override
|
||||
public ChannelInfo call() throws Exception {
|
||||
return ChannelInfo.getInfo(NewPipe.getService(serviceId), url);
|
||||
}
|
||||
}));
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
ChannelInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
public static Single<NextItemsResult> getMoreChannelItems(final int serviceId, final String url, final String nextStreamsUrl) {
|
||||
public static Single<NextItemsResult> getMoreChannelItems(final int serviceId,
|
||||
final String url,
|
||||
final String nextStreamsUrl) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(new Callable<NextItemsResult>() {
|
||||
@Override
|
||||
public NextItemsResult call() throws Exception {
|
||||
return ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
|
||||
}
|
||||
});
|
||||
return Single.fromCallable(() ->
|
||||
ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
|
||||
}
|
||||
|
||||
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId, final String url, boolean forceLoad) {
|
||||
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId,
|
||||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<PlaylistInfo>() {
|
||||
@Override
|
||||
public PlaylistInfo call() throws Exception {
|
||||
return PlaylistInfo.getInfo(NewPipe.getService(serviceId), url);
|
||||
}
|
||||
}));
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
PlaylistInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
public static Single<NextItemsResult> getMorePlaylistItems(final int serviceId, final String url, final String nextStreamsUrl) {
|
||||
public static Single<NextItemsResult> getMorePlaylistItems(final int serviceId,
|
||||
final String url,
|
||||
final String nextStreamsUrl) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(new Callable<NextItemsResult>() {
|
||||
@Override
|
||||
public NextItemsResult call() throws Exception {
|
||||
return PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
|
||||
}
|
||||
});
|
||||
return Single.fromCallable(() ->
|
||||
PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
|
||||
}
|
||||
|
||||
public static Single<KioskInfo> getKioskInfo(final int serviceId, final String url, final String contentCountry, boolean forceLoad) {
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<KioskInfo>() {
|
||||
@Override
|
||||
public KioskInfo call() throws Exception {
|
||||
Log.e("---------", contentCountry);
|
||||
return KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry);
|
||||
}
|
||||
}));
|
||||
public static Single<KioskInfo> getKioskInfo(final int serviceId,
|
||||
final String url,
|
||||
final String contentCountry,
|
||||
boolean forceLoad) {
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry)));
|
||||
}
|
||||
|
||||
public static Single<NextItemsResult> getMoreKioskItems(final int serviceId, final String url, final String nextStreamsUrl, final String contentCountry) {
|
||||
return Single.fromCallable(new Callable<NextItemsResult>() {
|
||||
@Override
|
||||
public NextItemsResult call() throws Exception {
|
||||
return KioskInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl, contentCountry);
|
||||
}
|
||||
});
|
||||
public static Single<NextItemsResult> getMoreKioskItems(final int serviceId,
|
||||
final String url,
|
||||
final String nextStreamsUrl,
|
||||
final String contentCountry) {
|
||||
return Single.fromCallable(() ->
|
||||
KioskInfo.getMoreItems(NewPipe.getService(serviceId),
|
||||
url, nextStreamsUrl, contentCountry));
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -163,24 +154,24 @@ public final class ExtractorHelper {
|
|||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
/**
|
||||
* Check if we can load it from the cache (forceLoad parameter), if we can't, load from the network (Single loadFromNetwork)
|
||||
* Check if we can load it from the cache (forceLoad parameter), if we can't,
|
||||
* load from the network (Single loadFromNetwork)
|
||||
* and put the results in the cache.
|
||||
*/
|
||||
private static <I extends Info> Single<I> checkCache(boolean forceLoad, int serviceId, String url, Single<I> loadFromNetwork) {
|
||||
private static <I extends Info> Single<I> checkCache(boolean forceLoad,
|
||||
int serviceId,
|
||||
String url,
|
||||
Single<I> loadFromNetwork) {
|
||||
checkServiceId(serviceId);
|
||||
loadFromNetwork = loadFromNetwork.doOnSuccess(new Consumer<I>() {
|
||||
@Override
|
||||
public void accept(@NonNull I i) throws Exception {
|
||||
cache.putInfo(i);
|
||||
}
|
||||
});
|
||||
loadFromNetwork = loadFromNetwork.doOnSuccess((@NonNull I i) -> cache.putInfo(i));
|
||||
|
||||
Single<I> load;
|
||||
if (forceLoad) {
|
||||
cache.removeInfo(serviceId, url);
|
||||
load = loadFromNetwork;
|
||||
} else {
|
||||
load = Maybe.concat(ExtractorHelper.<I>loadFromCache(serviceId, url), loadFromNetwork.toMaybe())
|
||||
load = Maybe.concat(ExtractorHelper.<I>loadFromCache(serviceId, url),
|
||||
loadFromNetwork.toMaybe())
|
||||
.firstElement() //Take the first valid
|
||||
.toSingle();
|
||||
}
|
||||
|
@ -193,9 +184,7 @@ public final class ExtractorHelper {
|
|||
*/
|
||||
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url) {
|
||||
checkServiceId(serviceId);
|
||||
return Maybe.defer(new Callable<MaybeSource<? extends I>>() {
|
||||
@Override
|
||||
public MaybeSource<? extends I> call() throws Exception {
|
||||
return Maybe.defer(() -> {
|
||||
//noinspection unchecked
|
||||
I info = (I) cache.getFromKey(serviceId, url);
|
||||
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
|
||||
|
@ -206,7 +195,6 @@ public final class ExtractorHelper {
|
|||
}
|
||||
|
||||
return Maybe.empty();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -215,7 +203,8 @@ public final class ExtractorHelper {
|
|||
*
|
||||
* @see Class#isAssignableFrom(Class)
|
||||
*/
|
||||
public static boolean hasAssignableCauseThrowable(Throwable throwable, Class<?>... causesToCheck) {
|
||||
public static boolean hasAssignableCauseThrowable(Throwable throwable,
|
||||
Class<?>... causesToCheck) {
|
||||
// Check if getCause is not the same as cause (the getCause is already the root),
|
||||
// as it will cause a infinite loop if it is
|
||||
Throwable cause, getCause = throwable;
|
||||
|
@ -270,7 +259,9 @@ public final class ExtractorHelper {
|
|||
* Check if throwable have Interrupted* exception as one of its causes.
|
||||
*/
|
||||
public static boolean isInterruptedCaused(Throwable throwable) {
|
||||
return ExtractorHelper.hasExactCauseThrowable(throwable, InterruptedIOException.class, InterruptedException.class);
|
||||
return ExtractorHelper.hasExactCauseThrowable(throwable,
|
||||
InterruptedIOException.class,
|
||||
InterruptedException.class);
|
||||
}
|
||||
|
||||
public static String toUpperCase(String value) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/**
|
||||
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
|
||||
* InfoCache.java is part of NewPipe
|
||||
*
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 20.01.18.
|
||||
* Copyright 2018 Christian Schabesberger <chris.schabesberger@mailbox.org>
|
||||
* PopupMenuIconHacker.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/>.
|
||||
*/
|
||||
|
||||
public class PopupMenuIconHacker {
|
||||
public static void setShowPopupIcon(PopupMenu menu) throws Exception {
|
||||
try {
|
||||
Field[] fields = menu.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if ("mPopup".equals(field.getName())) {
|
||||
field.setAccessible(true);
|
||||
Object menuPopupHelper = field.get(menu);
|
||||
Class<?> classPopupHelper = Class.forName(menuPopupHelper
|
||||
.getClass().getName());
|
||||
Method setForceIcons = classPopupHelper.getMethod(
|
||||
"setForceShowIcon", boolean.class);
|
||||
setForceIcons.invoke(menuPopupHelper, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new Exception("Could not make Popup menu show Icons", e);
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 103 B |
After Width: | Height: | Size: 478 B |
After Width: | Height: | Size: 93 B |
After Width: | Height: | Size: 321 B |
After Width: | Height: | Size: 111 B |
After Width: | Height: | Size: 645 B |
After Width: | Height: | Size: 122 B |
After Width: | Height: | Size: 916 B |
After Width: | Height: | Size: 123 B |
After Width: | Height: | Size: 1.2 KiB |
|
@ -1,18 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge
|
||||
<android.support.v4.widget.DrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context="org.schabi.newpipe.MainActivity">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"/>
|
||||
android:layout_marginTop="?attr/actionBarSize" />
|
||||
|
||||
<include layout="@layout/toolbar_layout"/>
|
||||
<include layout="@layout/toolbar_layout" />
|
||||
</FrameLayout>
|
||||
|
||||
</merge>
|
||||
<android.support.design.widget.NavigationView
|
||||
android:id="@+id/navigation"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
app:menu="@menu/drawer_items" />
|
||||
</android.support.v4.widget.DrawerLayout>
|
|
@ -244,7 +244,7 @@
|
|||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:scaleType="fitXY"
|
||||
android:src="?attr/options"
|
||||
android:src="@drawable/ic_more_vert_white_24dp"
|
||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
|
|
@ -273,7 +273,7 @@
|
|||
android:paddingBottom="6dp"
|
||||
android:paddingTop="6dp"
|
||||
android:text="@string/controls_background_title"
|
||||
android:textSize="12sp"/>
|
||||
android:textSize="12sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
<!--UPLOADER-->
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:title="@string/youtube" />
|
||||
<item android:title="@string/soundcloud" />
|
||||
</menu>
|
|
@ -4,17 +4,18 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:icon="@drawable/ic_screen_rotation_white"
|
||||
android:id="@+id/toggleOrientation"
|
||||
android:icon="@drawable/ic_screen_rotation_white"
|
||||
android:title="@string/toggle_orientation"
|
||||
app:showAsAction="always|withText" />
|
||||
<item
|
||||
android:icon="@drawable/ic_fullscreen_exit_white"
|
||||
android:id="@+id/switchPopup"
|
||||
android:icon="@drawable/ic_fullscreen_exit_white"
|
||||
android:title="@string/switch_to_popup"
|
||||
app:showAsAction="always|withText" />
|
||||
<item android:icon="?audio"
|
||||
<item
|
||||
android:id="@+id/switchBackground"
|
||||
android:icon="?audio"
|
||||
android:title="@string/switch_to_background"
|
||||
app:showAsAction="always|withText" />
|
||||
</menu>
|
||||
|
|
|
@ -46,6 +46,13 @@
|
|||
<item>144p</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="service_list" translatable="false">
|
||||
<item>@string/youtube</item>
|
||||
<item>@string/soundcloud</item>
|
||||
</string-array>
|
||||
<string name="service_key" translatable="false">service</string>
|
||||
<string name="default_service_value" translatable="false">@string/youtube</string>
|
||||
|
||||
<string name="video_mp4_key" translatable="false">video_mp4</string>
|
||||
<string name="video_webm_key" translatable="false">video_webm</string>
|
||||
<string name="video_3gp_key" translatable="false">video_3gp</string>
|
||||
|
|
|
@ -84,6 +84,7 @@
|
|||
<string name="show_hold_to_append_summary">Show tip when background or popup button is pressed on video details page</string>
|
||||
<string name="url_not_supported_toast">URL not supported</string>
|
||||
<string name="default_content_country_title">Default content country</string>
|
||||
<string name="service_title">Service</string>
|
||||
<string name="search_language_title">Default content language</string>
|
||||
<string name="settings_category_player_title">Player</string>
|
||||
<string name="settings_category_player_behavior_title">Behavior</string>
|
||||
|
@ -329,4 +330,10 @@
|
|||
<string name="start_here_on_main">Start Playing Here</string>
|
||||
<string name="start_here_on_background">Start Here on Background</string>
|
||||
<string name="start_here_on_popup">Start Here on Popup</string>
|
||||
|
||||
<!-- Drawer -->
|
||||
<string name="drawer_open">Open Drawer</string>
|
||||
<string name="drawer_close">Close Drawer</string>
|
||||
<string name="youtube" translatable="false">YouTube</string>
|
||||
<string name="soundcloud" translatable="false">SoundCloud</string>
|
||||
</resources>
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:title="@string/content">
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="@string/default_country_value"
|
||||
android:entries="@array/country_names"
|
||||
|
@ -38,5 +37,4 @@
|
|||
android:key="@string/main_page_content_key"
|
||||
android:title="@string/main_page_content"
|
||||
android:summary="%s"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|