Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
Weblate 2018-01-20 21:31:01 +01:00
commit 3634f68364
27 changed files with 286 additions and 160 deletions

View File

@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe" applicationId "org.schabi.newpipe"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 27 targetSdkVersion 27
versionCode 45 versionCode 46
versionName "0.11.4" versionName "0.11.5"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
@ -55,7 +55,7 @@ dependencies {
exclude module: 'support-annotations' exclude module: 'support-annotations'
} }
implementation 'com.github.TeamNewPipe:NewPipeExtractor:9de63f8c0a170a066' implementation 'com.github.TeamNewPipe:NewPipeExtractor:1c97da8b51b3610'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:1.10.19' testImplementation 'org.mockito:mockito-core:1.10.19'

View File

@ -28,8 +28,13 @@ import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.app.Fragment; 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.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; 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.HistoryEntry;
import org.schabi.newpipe.database.history.model.SearchHistoryEntry; import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
import org.schabi.newpipe.database.history.model.WatchHistoryEntry; 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.StreamingService;
import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.AudioStream;
import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamInfo;
@ -69,6 +75,7 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
private static final String TAG = "MainActivity"; private static final String TAG = "MainActivity";
public static final boolean DEBUG = false; public static final boolean DEBUG = false;
private SharedPreferences sharedPreferences; private SharedPreferences sharedPreferences;
private ActionBarDrawerToggle toggle = null;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Activity's LifeCycle // Activity's LifeCycle
@ -76,7 +83,8 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
@Override @Override
protected void onCreate(Bundle savedInstanceState) { 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); ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
@ -85,8 +93,59 @@ public class MainActivity extends AppCompatActivity implements HistoryListener {
initFragments(); 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); 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); sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
initHistory(); initHistory();

View File

@ -138,7 +138,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.action_search: case R.id.action_search:
NavigationHelper.openSearchFragment(getFragmentManager(), 0, ""); NavigationHelper.openSearchFragment(getFragmentManager(), NewPipe.getIdOfService(PreferenceManager.getDefaultSharedPreferences(getActivity()).getString("service", "YouTube")), "");
return true; return true;
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);

View File

@ -342,7 +342,11 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
} }
break; break;
case R.id.detail_thumbnail_root_layout: case R.id.detail_thumbnail_root_layout:
openVideoPlayer(); if (currentInfo.video_streams.isEmpty() && currentInfo.video_only_streams.isEmpty()) {
openBackgroundPlayer(false);
} else {
openVideoPlayer();
}
break; break;
case R.id.detail_title_root_layout: case R.id.detail_title_root_layout:
toggleTitleAndDescription(); 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); 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) { if (autoPlayEnabled) {
openVideoPlayer(); openVideoPlayer();
// Only auto play in the first open // Only auto play in the first open
@ -1201,4 +1212,4 @@ public class VideoDetailFragment extends BaseStateFragment<StreamInfo> implement
showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema); showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema);
} }
} }

View File

@ -124,20 +124,12 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
currentWorker = loadResult(forceLoad) currentWorker = loadResult(forceLoad)
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<I>() { .subscribe((@NonNull I result) -> {
@Override isLoading.set(false);
public void accept(@NonNull I result) throws Exception { currentInfo = result;
isLoading.set(false); currentNextItemsUrl = result.next_streams_url;
currentInfo = result; handleResult(result);
currentNextItemsUrl = result.next_streams_url; }, (@NonNull Throwable throwable) -> onError(throwable));
handleResult(result);
}
}, new Consumer<Throwable>() {
@Override
public void accept(@NonNull Throwable throwable) throws Exception {
onError(throwable);
}
});
} }
/** /**
@ -153,18 +145,12 @@ public abstract class BaseListInfoFragment<I extends ListInfo> extends BaseListF
currentWorker = loadMoreItemsLogic() currentWorker = loadMoreItemsLogic()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<ListExtractor.NextItemsResult>() { .subscribe((@io.reactivex.annotations.NonNull ListExtractor.NextItemsResult nextItemsResult) -> {
@Override isLoading.set(false);
public void accept(@io.reactivex.annotations.NonNull ListExtractor.NextItemsResult nextItemsResult) throws Exception { handleNextItems(nextItemsResult);
isLoading.set(false); }, (@io.reactivex.annotations.NonNull Throwable throwable) -> {
handleNextItems(nextItemsResult); isLoading.set(false);
} onError(throwable);
}, new Consumer<Throwable>() {
@Override
public void accept(@io.reactivex.annotations.NonNull Throwable throwable) throws Exception {
isLoading.set(false);
onError(throwable);
}
}); });
} }

View File

@ -25,6 +25,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Build; import android.os.Build;
@ -37,7 +38,6 @@ import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.WindowManager; 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.ListHelper;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.PopupMenuIconHacker;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -326,7 +327,7 @@ public final class MainVideoPlayer extends Activity {
this.playNextButton = rootView.findViewById(R.id.playNextButton); this.playNextButton = rootView.findViewById(R.id.playNextButton);
this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton); this.moreOptionsButton = rootView.findViewById(R.id.moreOptionsButton);
this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton); this.moreOptionsPopupMenu = new PopupMenu(context, moreOptionsButton);
this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions, moreOptionsPopupMenu.getMenu()); buildMoreOptionsMenu();
titleTextView.setSelected(true); titleTextView.setSelected(true);
channelTextView.setSelected(true); channelTextView.setSelected(true);
@ -379,7 +380,7 @@ public final class MainVideoPlayer extends Activity {
titleTextView.setText(getVideoTitle()); titleTextView.setText(getVideoTitle());
channelTextView.setText(getUploaderName()); channelTextView.setText(getUploaderName());
playPauseButton.setImageResource(R.drawable.ic_pause_white); //playPauseButton.setImageResource(R.drawable.ic_pause_white);
} }
@Override @Override
@ -499,25 +500,7 @@ public final class MainVideoPlayer extends Activity {
private void onMoreOptionsClicked() { private void onMoreOptionsClicked() {
if (DEBUG) Log.d(TAG, "onMoreOptionsClicked() called"); 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(); moreOptionsPopupMenu.show();
isSomePopupMenuVisible = true; isSomePopupMenuVisible = true;
showControls(300); showControls(300);
@ -659,7 +642,9 @@ public final class MainVideoPlayer extends Activity {
} }
private void buildMoreOptionsMenu() { private void buildMoreOptionsMenu() {
if (moreOptionsPopupMenu == null) return; this.moreOptionsPopupMenu.getMenuInflater().inflate(R.menu.menu_videooptions,
moreOptionsPopupMenu.getMenu());
moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> { moreOptionsPopupMenu.setOnMenuItemClickListener(menuItem -> {
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
case R.id.toggleOrientation: case R.id.toggleOrientation:
@ -674,6 +659,22 @@ public final class MainVideoPlayer extends Activity {
} }
return false; 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() { private void buildQueue() {

View File

@ -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); checkServiceId(serviceId);
return Single.fromCallable(new Callable<SearchResult>() { return Single.fromCallable(() ->
@Override SearchResult.getSearchResult(NewPipe.getService(serviceId).getSearchEngine(),
public SearchResult call() throws Exception { query, pageNumber, contentCountry, filter)
return 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); checkServiceId(serviceId);
return searchFor(serviceId, query, nextPageNumber, searchLanguage, filter) return searchFor(serviceId, query, nextPageNumber, searchLanguage, filter)
.map(new Function<SearchResult, NextItemsResult>() { .map((@NonNull SearchResult searchResult) ->
@Override new NextItemsResult(searchResult.resultList,
public NextItemsResult apply(@NonNull SearchResult searchResult) throws Exception { nextPageNumber + "",
return new NextItemsResult(searchResult.resultList, nextPageNumber + "", searchResult.errors); 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); checkServiceId(serviceId);
return Single.fromCallable(new Callable<List<String>>() { return Single.fromCallable(() ->
@Override NewPipe.getService(serviceId)
public List<String> call() throws Exception { .getSuggestionExtractor()
return NewPipe.getService(serviceId).getSuggestionExtractor().suggestionList(query, contentCountry); .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); checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<StreamInfo>() { return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
@Override StreamInfo.getInfo(NewPipe.getService(serviceId), url)));
public StreamInfo call() throws Exception {
return 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); checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<ChannelInfo>() { return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
@Override ChannelInfo.getInfo(NewPipe.getService(serviceId), url)));
public ChannelInfo call() throws Exception {
return 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); checkServiceId(serviceId);
return Single.fromCallable(new Callable<NextItemsResult>() { return Single.fromCallable(() ->
@Override ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
public NextItemsResult call() throws Exception {
return 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); checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<PlaylistInfo>() { return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
@Override PlaylistInfo.getInfo(NewPipe.getService(serviceId), url)));
public PlaylistInfo call() throws Exception {
return 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); checkServiceId(serviceId);
return Single.fromCallable(new Callable<NextItemsResult>() { return Single.fromCallable(() ->
@Override PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
public NextItemsResult call() throws Exception {
return PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl);
}
});
} }
public static Single<KioskInfo> getKioskInfo(final int serviceId, final String url, final String contentCountry, boolean forceLoad) { public static Single<KioskInfo> getKioskInfo(final int serviceId,
return checkCache(forceLoad, serviceId, url, Single.fromCallable(new Callable<KioskInfo>() { final String url,
@Override final String contentCountry,
public KioskInfo call() throws Exception { boolean forceLoad) {
Log.e("---------", contentCountry); return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
return KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry); KioskInfo.getInfo(NewPipe.getService(serviceId), url, contentCountry)));
}
}));
} }
public static Single<NextItemsResult> getMoreKioskItems(final int serviceId, final String url, final String nextStreamsUrl, final String contentCountry) { public static Single<NextItemsResult> getMoreKioskItems(final int serviceId,
return Single.fromCallable(new Callable<NextItemsResult>() { final String url,
@Override final String nextStreamsUrl,
public NextItemsResult call() throws Exception { final String contentCountry) {
return KioskInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl, 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. * 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); checkServiceId(serviceId);
loadFromNetwork = loadFromNetwork.doOnSuccess(new Consumer<I>() { loadFromNetwork = loadFromNetwork.doOnSuccess((@NonNull I i) -> cache.putInfo(i));
@Override
public void accept(@NonNull I i) throws Exception {
cache.putInfo(i);
}
});
Single<I> load; Single<I> load;
if (forceLoad) { if (forceLoad) {
cache.removeInfo(serviceId, url); cache.removeInfo(serviceId, url);
load = loadFromNetwork; load = loadFromNetwork;
} else { } 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 .firstElement() //Take the first valid
.toSingle(); .toSingle();
} }
@ -193,9 +184,7 @@ public final class ExtractorHelper {
*/ */
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url) { public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url) {
checkServiceId(serviceId); checkServiceId(serviceId);
return Maybe.defer(new Callable<MaybeSource<? extends I>>() { return Maybe.defer(() -> {
@Override
public MaybeSource<? extends I> call() throws Exception {
//noinspection unchecked //noinspection unchecked
I info = (I) cache.getFromKey(serviceId, url); I info = (I) cache.getFromKey(serviceId, url);
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info); if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
@ -206,8 +195,7 @@ public final class ExtractorHelper {
} }
return Maybe.empty(); return Maybe.empty();
} });
});
} }
/** /**
@ -215,7 +203,8 @@ public final class ExtractorHelper {
* *
* @see Class#isAssignableFrom(Class) * @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), // 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 // as it will cause a infinite loop if it is
Throwable cause, getCause = throwable; Throwable cause, getCause = throwable;
@ -270,7 +259,9 @@ public final class ExtractorHelper {
* Check if throwable have Interrupted* exception as one of its causes. * Check if throwable have Interrupted* exception as one of its causes.
*/ */
public static boolean isInterruptedCaused(Throwable throwable) { 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) { public static String toUpperCase(String value) {

View File

@ -1,4 +1,4 @@
/* /**
* Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com> * Copyright 2017 Mauricio Colli <mauriciocolli@outlook.com>
* InfoCache.java is part of NewPipe * InfoCache.java is part of NewPipe
* *

View File

@ -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);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 645 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,18 +1,30 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merge <android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android" 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" xmlns:tools="http://schemas.android.com/tools"
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">
android:orientation="vertical"
tools:context="org.schabi.newpipe.MainActivity">
<FrameLayout <FrameLayout
android:id="@+id/fragment_holder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize"/> 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" />
<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>

View File

@ -244,7 +244,7 @@
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="?attr/options" android:src="@drawable/ic_more_vert_white_24dp"
tools:ignore="ContentDescription,RtlHardcoded"/> tools:ignore="ContentDescription,RtlHardcoded"/>
</RelativeLayout> </RelativeLayout>

View File

@ -273,7 +273,7 @@
android:paddingBottom="6dp" android:paddingBottom="6dp"
android:paddingTop="6dp" android:paddingTop="6dp"
android:text="@string/controls_background_title" android:text="@string/controls_background_title"
android:textSize="12sp"/> android:textSize="12sp" />
</RelativeLayout> </RelativeLayout>
<!--UPLOADER--> <!--UPLOADER-->

View File

@ -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>

View File

@ -4,17 +4,18 @@
xmlns:android="http://schemas.android.com/apk/res/android" 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">
<item <item
android:icon="@drawable/ic_screen_rotation_white"
android:id="@+id/toggleOrientation" android:id="@+id/toggleOrientation"
android:icon="@drawable/ic_screen_rotation_white"
android:title="@string/toggle_orientation" android:title="@string/toggle_orientation"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
<item <item
android:icon="@drawable/ic_fullscreen_exit_white"
android:id="@+id/switchPopup" android:id="@+id/switchPopup"
android:icon="@drawable/ic_fullscreen_exit_white"
android:title="@string/switch_to_popup" android:title="@string/switch_to_popup"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
<item android:icon="?audio" <item
android:id="@+id/switchBackground" android:id="@+id/switchBackground"
android:icon="?audio"
android:title="@string/switch_to_background" android:title="@string/switch_to_background"
app:showAsAction="always|withText" /> app:showAsAction="always|withText" />
</menu> </menu>

View File

@ -46,6 +46,13 @@
<item>144p</item> <item>144p</item>
</string-array> </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_mp4_key" translatable="false">video_mp4</string>
<string name="video_webm_key" translatable="false">video_webm</string> <string name="video_webm_key" translatable="false">video_webm</string>
<string name="video_3gp_key" translatable="false">video_3gp</string> <string name="video_3gp_key" translatable="false">video_3gp</string>

View File

@ -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="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="url_not_supported_toast">URL not supported</string>
<string name="default_content_country_title">Default content country</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="search_language_title">Default content language</string>
<string name="settings_category_player_title">Player</string> <string name="settings_category_player_title">Player</string>
<string name="settings_category_player_behavior_title">Behavior</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_main">Start Playing Here</string>
<string name="start_here_on_background">Start Here on Background</string> <string name="start_here_on_background">Start Here on Background</string>
<string name="start_here_on_popup">Start Here on Popup</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> </resources>

View File

@ -2,7 +2,6 @@
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/content"> android:title="@string/content">
<ListPreference <ListPreference
android:defaultValue="@string/default_country_value" android:defaultValue="@string/default_country_value"
android:entries="@array/country_names" android:entries="@array/country_names"
@ -38,5 +37,4 @@
android:key="@string/main_page_content_key" android:key="@string/main_page_content_key"
android:title="@string/main_page_content" android:title="@string/main_page_content"
android:summary="%s"/> android:summary="%s"/>
</PreferenceScreen> </PreferenceScreen>