mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-12-23 16:40:32 +00:00
Merge branch 'search' into dev
This commit is contained in:
commit
3a44e92432
@ -54,7 +54,7 @@ dependencies {
|
||||
exclude module: 'support-annotations'
|
||||
}
|
||||
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:bf1c771'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:1eff8c5708'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:2.8.9'
|
||||
|
@ -61,6 +61,8 @@ import org.schabi.newpipe.util.ServiceHelper;
|
||||
import org.schabi.newpipe.util.StateSaver;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import static org.schabi.newpipe.extractor.InfoItem.InfoType.PLAYLIST;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||
@ -392,31 +394,45 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
|
||||
try {
|
||||
if (DEBUG) Log.d(TAG, "handleIntent() called with: intent = [" + intent + "]");
|
||||
|
||||
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
|
||||
String url = intent.getStringExtra(Constants.KEY_URL);
|
||||
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||
String title = intent.getStringExtra(Constants.KEY_TITLE);
|
||||
switch (((StreamingService.LinkType) intent.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
||||
case STREAM:
|
||||
boolean autoPlay = intent.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
||||
NavigationHelper.openVideoDetailFragment(getSupportFragmentManager(), serviceId, url, title, autoPlay);
|
||||
break;
|
||||
case CHANNEL:
|
||||
NavigationHelper.openChannelFragment(getSupportFragmentManager(), serviceId, url, title);
|
||||
break;
|
||||
case PLAYLIST:
|
||||
NavigationHelper.openPlaylistFragment(getSupportFragmentManager(), serviceId, url, title);
|
||||
break;
|
||||
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
|
||||
String url = intent.getStringExtra(Constants.KEY_URL);
|
||||
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||
String title = intent.getStringExtra(Constants.KEY_TITLE);
|
||||
switch (((StreamingService.LinkType) intent.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
||||
case STREAM:
|
||||
boolean autoPlay = intent.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
||||
NavigationHelper.openVideoDetailFragment(getSupportFragmentManager(), serviceId, url, title, autoPlay);
|
||||
break;
|
||||
case CHANNEL:
|
||||
NavigationHelper.openChannelFragment(getSupportFragmentManager(),
|
||||
serviceId,
|
||||
url,
|
||||
title);
|
||||
break;
|
||||
case PLAYLIST:
|
||||
NavigationHelper.openPlaylistFragment(getSupportFragmentManager(),
|
||||
serviceId,
|
||||
url,
|
||||
title);
|
||||
break;
|
||||
}
|
||||
} else if (intent.hasExtra(Constants.KEY_OPEN_SEARCH)) {
|
||||
String searchString = intent.getStringExtra(Constants.KEY_SEARCH_STRING);
|
||||
if (searchString == null) searchString = "";
|
||||
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||
NavigationHelper.openSearchFragment(
|
||||
getSupportFragmentManager(),
|
||||
serviceId,
|
||||
searchString);
|
||||
|
||||
} else {
|
||||
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
|
||||
}
|
||||
} else if (intent.hasExtra(Constants.KEY_OPEN_SEARCH)) {
|
||||
String searchQuery = intent.getStringExtra(Constants.KEY_QUERY);
|
||||
if (searchQuery == null) searchQuery = "";
|
||||
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||
NavigationHelper.openSearchFragment(getSupportFragmentManager(), serviceId, searchQuery);
|
||||
} else {
|
||||
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@ -127,7 +128,14 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_search:
|
||||
NavigationHelper.openSearchFragment(getFragmentManager(), ServiceHelper.getSelectedServiceId(activity), "");
|
||||
try {
|
||||
NavigationHelper.openSearchFragment(
|
||||
getFragmentManager(),
|
||||
ServiceHelper.getSelectedServiceId(activity),
|
||||
"");
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
@ -226,7 +234,9 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
FALLBACK_CHANNEL_URL);
|
||||
String name = preferences.getString(getString(R.string.main_page_selected_channel_name),
|
||||
FALLBACK_CHANNEL_NAME);
|
||||
ChannelFragment fragment = ChannelFragment.getInstance(serviceId, url, name);
|
||||
ChannelFragment fragment = ChannelFragment.getInstance(serviceId,
|
||||
url,
|
||||
name);
|
||||
fragment.useAsFrontPage(true);
|
||||
return fragment;
|
||||
} else {
|
||||
@ -255,20 +265,13 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||
for (final String ks : kl.getAvailableKiosks()) {
|
||||
menu.add(0, KIOSK_MENU_OFFSET + i, Menu.NONE,
|
||||
KioskTranslator.getTranslatedKioskName(ks, getContext()))
|
||||
.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
.setOnMenuItemClickListener(menuItem -> {
|
||||
try {
|
||||
NavigationHelper.openKioskFragment(getFragmentManager(), currentServiceId, ks);
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportError(activity, e,
|
||||
activity.getClass(),
|
||||
null,
|
||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||
"none", "", R.string.app_ui_crash));
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
i++;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
@ -54,7 +55,7 @@ import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.Stream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
@ -64,6 +65,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.fragments.BackPressable;
|
||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.util.StreamItemAdapter;
|
||||
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||
@ -365,11 +367,15 @@ public class VideoDetailFragment
|
||||
if (TextUtils.isEmpty(currentInfo.getUploaderUrl())) {
|
||||
Log.w(TAG, "Can't open channel because we got no channel URL");
|
||||
} else {
|
||||
NavigationHelper.openChannelFragment(
|
||||
getFragmentManager(),
|
||||
currentInfo.getServiceId(),
|
||||
currentInfo.getUploaderUrl(),
|
||||
currentInfo.getUploaderName());
|
||||
try {
|
||||
NavigationHelper.openChannelFragment(
|
||||
getFragmentManager(),
|
||||
currentInfo.getServiceId(),
|
||||
currentInfo.getUploaderUrl(),
|
||||
currentInfo.getUploaderName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R.id.detail_thumbnail_root_layout:
|
||||
|
@ -6,6 +6,7 @@ import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
@ -24,6 +25,7 @@ import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.OnClickGesture;
|
||||
import org.schabi.newpipe.util.StateSaver;
|
||||
@ -152,18 +154,35 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
||||
@Override
|
||||
public void selected(ChannelInfoItem selectedItem) {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openChannelFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
try {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openChannelFragment(useAsFrontPage ?
|
||||
getParentFragment().getFragmentManager()
|
||||
: getFragmentManager(),
|
||||
selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
infoListAdapter.setOnPlaylistSelectedListener(new OnClickGesture<PlaylistInfoItem>() {
|
||||
@Override
|
||||
public void selected(PlaylistInfoItem selectedItem) {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openPlaylistFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
try {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openPlaylistFragment(
|
||||
useAsFrontPage
|
||||
? getParentFragment().getFragmentManager()
|
||||
: getFragmentManager(),
|
||||
selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -178,7 +197,9 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
||||
|
||||
private void onStreamSelected(StreamInfoItem selectedItem) {
|
||||
onItemSelected(selectedItem);
|
||||
NavigationHelper.openVideoDetailFragment(useAsFrontPage ? getParentFragment().getFragmentManager() : getFragmentManager(),
|
||||
NavigationHelper.openVideoDetailFragment(useAsFrontPage
|
||||
? getParentFragment().getFragmentManager()
|
||||
: getFragmentManager(),
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,9 @@ import android.view.View;
|
||||
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.ListInfo;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
|
||||
import java.util.Queue;
|
||||
@ -166,7 +169,6 @@ public abstract class BaseListInfoFragment<I extends ListInfo>
|
||||
public void handleResult(@NonNull I result) {
|
||||
super.handleResult(result);
|
||||
|
||||
url = result.getUrl();
|
||||
name = result.getName();
|
||||
setTitle(name);
|
||||
|
||||
|
@ -33,6 +33,7 @@ import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||
@ -501,7 +502,11 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo> {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.REQUESTED_CHANNEL, NewPipe.getNameOfService(serviceId), url, errorId);
|
||||
onUnrecoverableError(exception,
|
||||
UserAction.REQUESTED_CHANNEL,
|
||||
NewPipe.getNameOfService(serviceId),
|
||||
url,
|
||||
errorId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -11,22 +11,20 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.UrlIdHandler;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.KioskTranslator;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
|
||||
import icepick.State;
|
||||
import io.reactivex.Single;
|
||||
@ -74,10 +72,10 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
throws ExtractionException {
|
||||
KioskFragment instance = new KioskFragment();
|
||||
StreamingService service = NewPipe.getService(serviceId);
|
||||
UrlIdHandler kioskTypeUrlIdHandler = service.getKioskList()
|
||||
.getUrlIdHandlerByType(kioskId);
|
||||
ListLinkHandlerFactory kioskLinkHandlerFactory = service.getKioskList()
|
||||
.getListLinkHandlerFactoryByType(kioskId);
|
||||
instance.setInitialData(serviceId,
|
||||
kioskTypeUrlIdHandler.getUrl(kioskId), kioskId);
|
||||
kioskLinkHandlerFactory.fromId(kioskId).getUrl(), kioskId);
|
||||
instance.kioskId = kioskId;
|
||||
return instance;
|
||||
}
|
||||
@ -136,7 +134,10 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
.getDefaultSharedPreferences(activity)
|
||||
.getString(getString(R.string.content_country_key),
|
||||
getString(R.string.default_country_value));
|
||||
return ExtractorHelper.getKioskInfo(serviceId, url, contentCountry, forceReload);
|
||||
return ExtractorHelper.getKioskInfo(serviceId,
|
||||
url,
|
||||
contentCountry,
|
||||
forceReload);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -145,7 +146,10 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
||||
.getDefaultSharedPreferences(activity)
|
||||
.getString(getString(R.string.content_country_key),
|
||||
getString(R.string.default_country_value));
|
||||
return ExtractorHelper.getMoreKioskItems(serviceId, url, currentNextPageUrl, contentCountry);
|
||||
return ExtractorHelper.getMoreKioskItems(serviceId,
|
||||
url,
|
||||
currentNextPageUrl,
|
||||
contentCountry);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -6,6 +6,7 @@ import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@ -19,6 +20,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.schabi.newpipe.App;
|
||||
import org.schabi.newpipe.NewPipeDatabase;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||
@ -28,12 +30,14 @@ import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||
@ -267,11 +271,16 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
if (!TextUtils.isEmpty(result.getUploaderName())) {
|
||||
headerUploaderName.setText(result.getUploaderName());
|
||||
if (!TextUtils.isEmpty(result.getUploaderUrl())) {
|
||||
headerUploaderLayout.setOnClickListener(v ->
|
||||
headerUploaderLayout.setOnClickListener(v -> {
|
||||
try {
|
||||
NavigationHelper.openChannelFragment(getFragmentManager(),
|
||||
result.getServiceId(), result.getUploaderUrl(),
|
||||
result.getUploaderName())
|
||||
);
|
||||
result.getServiceId(),
|
||||
result.getUploaderUrl(),
|
||||
result.getUploaderName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -339,7 +348,11 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.REQUESTED_PLAYLIST, NewPipe.getNameOfService(serviceId), url, errorId);
|
||||
onUnrecoverableError(exception,
|
||||
UserAction.REQUESTED_PLAYLIST,
|
||||
NewPipe.getNameOfService(serviceId),
|
||||
url,
|
||||
errorId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,8 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.stetho.common.ListUtil;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.ReCaptchaActivity;
|
||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
||||
@ -37,26 +39,28 @@ import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||
import org.schabi.newpipe.extractor.search.SearchInfo;
|
||||
import org.schabi.newpipe.fragments.BackPressable;
|
||||
import org.schabi.newpipe.fragments.list.BaseListFragment;
|
||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.LayoutManagerSmoothScroller;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ServiceHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.SocketException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import icepick.State;
|
||||
@ -65,14 +69,15 @@ import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import io.reactivex.subjects.PublishSubject;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
public class SearchFragment
|
||||
extends BaseListFragment<SearchResult, ListExtractor.InfoItemsPage>
|
||||
extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage>
|
||||
implements BackPressable {
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -92,19 +97,28 @@ public class SearchFragment
|
||||
|
||||
@State
|
||||
protected int filterItemCheckedId = -1;
|
||||
private SearchEngine.Filter filter = SearchEngine.Filter.ANY;
|
||||
|
||||
@State
|
||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||
|
||||
// this three represet the current search query
|
||||
@State
|
||||
protected String searchQuery;
|
||||
protected String searchString;
|
||||
@State
|
||||
protected String lastSearchedQuery;
|
||||
protected String[] contentFilter;
|
||||
@State
|
||||
protected String sortFilter;
|
||||
|
||||
// these represtent the last search
|
||||
@State
|
||||
protected String lastSearchedString;
|
||||
|
||||
@State
|
||||
protected boolean wasSearchFocused = false;
|
||||
|
||||
private int currentPage = 0;
|
||||
private int currentNextPage = 0;
|
||||
private StreamingService service;
|
||||
private String currentPageUrl;
|
||||
private String nextPageUrl;
|
||||
private String contentCountry;
|
||||
private boolean isSuggestionsEnabled = true;
|
||||
private boolean isSearchHistoryEnabled = true;
|
||||
@ -130,11 +144,11 @@ public class SearchFragment
|
||||
|
||||
/*////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public static SearchFragment getInstance(int serviceId, String query) {
|
||||
public static SearchFragment getInstance(int serviceId, String searchString) {
|
||||
SearchFragment searchFragment = new SearchFragment();
|
||||
searchFragment.setQuery(serviceId, query);
|
||||
searchFragment.setQuery(serviceId, searchString, new String[0], "");
|
||||
|
||||
if (!TextUtils.isEmpty(query)) {
|
||||
if (!TextUtils.isEmpty(searchString)) {
|
||||
searchFragment.setSearchOnResume();
|
||||
}
|
||||
|
||||
@ -202,13 +216,22 @@ public class SearchFragment
|
||||
if (DEBUG) Log.d(TAG, "onResume() called");
|
||||
super.onResume();
|
||||
|
||||
if (!TextUtils.isEmpty(searchQuery)) {
|
||||
try {
|
||||
service = NewPipe.getService(serviceId);
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportError(getActivity(), e, getActivity().getClass(),
|
||||
getActivity().findViewById(android.R.id.content),
|
||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||
"",
|
||||
"", R.string.general_error));
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(searchString)) {
|
||||
if (wasLoading.getAndSet(false)) {
|
||||
if (currentNextPage > currentPage) loadMoreItems();
|
||||
else search(searchQuery);
|
||||
search(searchString, contentFilter, sortFilter);
|
||||
} else if (infoListAdapter.getItemsList().size() == 0) {
|
||||
if (savedState == null) {
|
||||
search(searchQuery);
|
||||
search(searchString, contentFilter, sortFilter);
|
||||
} else if (!isLoading.get() && !wasSearchFocused) {
|
||||
infoListAdapter.clearStreamItemList();
|
||||
showEmptyState();
|
||||
@ -218,7 +241,7 @@ public class SearchFragment
|
||||
|
||||
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) initSuggestionObserver();
|
||||
|
||||
if (TextUtils.isEmpty(searchQuery) || wasSearchFocused) {
|
||||
if (TextUtils.isEmpty(searchString) || wasSearchFocused) {
|
||||
showKeyboardSearch();
|
||||
showSuggestionsPanel();
|
||||
} else {
|
||||
@ -247,8 +270,9 @@ public class SearchFragment
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
||||
if (resultCode == Activity.RESULT_OK && !TextUtils.isEmpty(searchQuery)) {
|
||||
search(searchQuery);
|
||||
if (resultCode == Activity.RESULT_OK
|
||||
&& !TextUtils.isEmpty(searchString)) {
|
||||
search(searchString, contentFilter, sortFilter);
|
||||
} else Log.e(TAG, "ReCaptcha failed");
|
||||
break;
|
||||
|
||||
@ -282,20 +306,22 @@ public class SearchFragment
|
||||
@Override
|
||||
public void writeTo(Queue<Object> objectsToSave) {
|
||||
super.writeTo(objectsToSave);
|
||||
objectsToSave.add(currentPage);
|
||||
objectsToSave.add(currentNextPage);
|
||||
objectsToSave.add(currentPageUrl);
|
||||
objectsToSave.add(nextPageUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(@NonNull Queue<Object> savedObjects) throws Exception {
|
||||
super.readFrom(savedObjects);
|
||||
currentPage = (int) savedObjects.poll();
|
||||
currentNextPage = (int) savedObjects.poll();
|
||||
currentPageUrl = (String) savedObjects.poll();
|
||||
nextPageUrl = (String) savedObjects.poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle bundle) {
|
||||
searchQuery = searchEditText != null ? searchEditText.getText().toString() : searchQuery;
|
||||
searchString = searchEditText != null
|
||||
? searchEditText.getText().toString()
|
||||
: searchString;
|
||||
super.onSaveInstanceState(bundle);
|
||||
}
|
||||
|
||||
@ -305,8 +331,11 @@ public class SearchFragment
|
||||
|
||||
@Override
|
||||
public void reloadContent() {
|
||||
if (!TextUtils.isEmpty(searchQuery) || (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
|
||||
search(!TextUtils.isEmpty(searchQuery) ? searchQuery : searchEditText.getText().toString());
|
||||
if (!TextUtils.isEmpty(searchString)
|
||||
|| (searchEditText != null && !TextUtils.isEmpty(searchEditText.getText()))) {
|
||||
search(!TextUtils.isEmpty(searchString)
|
||||
? searchString
|
||||
: searchEditText.getText().toString(), new String[0], "");
|
||||
} else {
|
||||
if (searchEditText != null) {
|
||||
searchEditText.setText("");
|
||||
@ -330,22 +359,32 @@ public class SearchFragment
|
||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
inflater.inflate(R.menu.menu_search, menu);
|
||||
int itemId = 0;
|
||||
boolean isFirstItem = true;
|
||||
final Context c = getContext();
|
||||
for(String filter : service.getSearchQIHFactory().getAvailableContentFilter()) {
|
||||
MenuItem item = menu.add(1,
|
||||
itemId++,
|
||||
0,
|
||||
ServiceHelper.getTranslatedFilterString(filter, c));
|
||||
if(isFirstItem) {
|
||||
item.setChecked(true);
|
||||
isFirstItem = false;
|
||||
}
|
||||
}
|
||||
menu.setGroupCheckable(1, true, true);
|
||||
|
||||
restoreFilterChecked(menu, filterItemCheckedId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_filter_all:
|
||||
case R.id.menu_filter_video:
|
||||
case R.id.menu_filter_channel:
|
||||
case R.id.menu_filter_playlist:
|
||||
changeFilter(item, getFilterFromMenuId(item.getItemId()));
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
List<String> contentFilter = new ArrayList<>(1);
|
||||
contentFilter.add(item.getTitle().toString());
|
||||
changeContentFilter(item, contentFilter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void restoreFilterChecked(Menu menu, int itemId) {
|
||||
@ -354,21 +393,6 @@ public class SearchFragment
|
||||
if (item == null) return;
|
||||
|
||||
item.setChecked(true);
|
||||
filter = getFilterFromMenuId(itemId);
|
||||
}
|
||||
}
|
||||
|
||||
private SearchEngine.Filter getFilterFromMenuId(int itemId) {
|
||||
switch (itemId) {
|
||||
case R.id.menu_filter_video:
|
||||
return SearchEngine.Filter.STREAM;
|
||||
case R.id.menu_filter_channel:
|
||||
return SearchEngine.Filter.CHANNEL;
|
||||
case R.id.menu_filter_playlist:
|
||||
return SearchEngine.Filter.PLAYLIST;
|
||||
case R.id.menu_filter_all:
|
||||
default:
|
||||
return SearchEngine.Filter.ANY;
|
||||
}
|
||||
}
|
||||
|
||||
@ -379,14 +403,21 @@ public class SearchFragment
|
||||
private TextWatcher textWatcher;
|
||||
|
||||
private void showSearchOnStart() {
|
||||
if (DEBUG) Log.d(TAG, "showSearchOnStart() called, searchQuery → " + searchQuery+", lastSearchedQuery → " + lastSearchedQuery);
|
||||
searchEditText.setText(searchQuery);
|
||||
if (DEBUG) Log.d(TAG, "showSearchOnStart() called, searchQuery → "
|
||||
+ searchString
|
||||
+ ", lastSearchedQuery → "
|
||||
+ lastSearchedString);
|
||||
searchEditText.setText(searchString);
|
||||
|
||||
if (TextUtils.isEmpty(searchQuery) || TextUtils.isEmpty(searchEditText.getText())) {
|
||||
if (TextUtils.isEmpty(searchString) || TextUtils.isEmpty(searchEditText.getText())) {
|
||||
searchToolbarContainer.setTranslationX(100);
|
||||
searchToolbarContainer.setAlpha(0f);
|
||||
searchToolbarContainer.setVisibility(View.VISIBLE);
|
||||
searchToolbarContainer.animate().translationX(0).alpha(1f).setDuration(200).setInterpolator(new DecelerateInterpolator()).start();
|
||||
searchToolbarContainer.animate()
|
||||
.translationX(0)
|
||||
.alpha(1f)
|
||||
.setDuration(200)
|
||||
.setInterpolator(new DecelerateInterpolator()).start();
|
||||
} else {
|
||||
searchToolbarContainer.setTranslationX(0);
|
||||
searchToolbarContainer.setAlpha(1f);
|
||||
@ -396,47 +427,38 @@ public class SearchFragment
|
||||
|
||||
private void initSearchListeners() {
|
||||
if (DEBUG) Log.d(TAG, "initSearchListeners() called");
|
||||
searchClear.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (DEBUG) Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||
if (TextUtils.isEmpty(searchEditText.getText())) {
|
||||
NavigationHelper.gotoMainFragment(getFragmentManager());
|
||||
return;
|
||||
}
|
||||
|
||||
searchEditText.setText("");
|
||||
suggestionListAdapter.setItems(new ArrayList<SuggestionItem>());
|
||||
showKeyboardSearch();
|
||||
searchClear.setOnClickListener(v -> {
|
||||
if (DEBUG) Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||
if (TextUtils.isEmpty(searchEditText.getText())) {
|
||||
NavigationHelper.gotoMainFragment(getFragmentManager());
|
||||
return;
|
||||
}
|
||||
|
||||
searchEditText.setText("");
|
||||
suggestionListAdapter.setItems(new ArrayList<>());
|
||||
showKeyboardSearch();
|
||||
});
|
||||
|
||||
TooltipCompat.setTooltipText(searchClear, getString(R.string.clear));
|
||||
|
||||
searchEditText.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (DEBUG) Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||
if (isSuggestionsEnabled && errorPanelRoot.getVisibility() != View.VISIBLE) {
|
||||
showSuggestionsPanel();
|
||||
}
|
||||
searchEditText.setOnClickListener(v -> {
|
||||
if (DEBUG) Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||
if (isSuggestionsEnabled && errorPanelRoot.getVisibility() != View.VISIBLE) {
|
||||
showSuggestionsPanel();
|
||||
}
|
||||
});
|
||||
|
||||
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||
@Override
|
||||
public void onFocusChange(View v, boolean hasFocus) {
|
||||
if (DEBUG) Log.d(TAG, "onFocusChange() called with: v = [" + v + "], hasFocus = [" + hasFocus + "]");
|
||||
if (isSuggestionsEnabled && hasFocus && errorPanelRoot.getVisibility() != View.VISIBLE) {
|
||||
showSuggestionsPanel();
|
||||
}
|
||||
searchEditText.setOnFocusChangeListener((View v, boolean hasFocus) -> {
|
||||
if (DEBUG) Log.d(TAG, "onFocusChange() called with: v = [" + v + "], hasFocus = [" + hasFocus + "]");
|
||||
if (isSuggestionsEnabled && hasFocus && errorPanelRoot.getVisibility() != View.VISIBLE) {
|
||||
showSuggestionsPanel();
|
||||
}
|
||||
});
|
||||
|
||||
suggestionListAdapter.setListener(new SuggestionListAdapter.OnSuggestionItemSelected() {
|
||||
@Override
|
||||
public void onSuggestionItemSelected(SuggestionItem item) {
|
||||
search(item.query);
|
||||
search(item.query, new String[0], "");
|
||||
searchEditText.setText(item.query);
|
||||
}
|
||||
|
||||
@ -469,21 +491,22 @@ public class SearchFragment
|
||||
}
|
||||
};
|
||||
searchEditText.addTextChangedListener(textWatcher);
|
||||
searchEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onEditorAction() called with: v = [" + v + "], actionId = [" + actionId + "], event = [" + event + "]");
|
||||
}
|
||||
if (event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER || event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
|
||||
search(searchEditText.getText().toString());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
searchEditText.setOnEditorActionListener(
|
||||
(TextView v, int actionId, KeyEvent event) -> {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onEditorAction() called with: v = [" + v + "], actionId = [" + actionId + "], event = [" + event + "]");
|
||||
}
|
||||
if (event != null
|
||||
&& (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
|
||||
|| event.getAction() == EditorInfo.IME_ACTION_SEARCH)) {
|
||||
search(searchEditText.getText().toString(), new String[0], "");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (suggestionDisposable == null || suggestionDisposable.isDisposed()) initSuggestionObserver();
|
||||
if (suggestionDisposable == null || suggestionDisposable.isDisposed())
|
||||
initSuggestionObserver();
|
||||
}
|
||||
|
||||
private void unsetSearchListeners() {
|
||||
@ -513,7 +536,8 @@ public class SearchFragment
|
||||
if (searchEditText == null) return;
|
||||
|
||||
if (searchEditText.requestFocus()) {
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_IMPLICIT);
|
||||
}
|
||||
}
|
||||
@ -522,8 +546,10 @@ public class SearchFragment
|
||||
if (DEBUG) Log.d(TAG, "hideKeyboardSearch() called");
|
||||
if (searchEditText == null) return;
|
||||
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
|
||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(
|
||||
Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(),
|
||||
InputMethodManager.HIDE_NOT_ALWAYS);
|
||||
|
||||
searchEditText.clearFocus();
|
||||
}
|
||||
@ -554,10 +580,12 @@ public class SearchFragment
|
||||
|
||||
@Override
|
||||
public boolean onBackPressed() {
|
||||
if (suggestionsPanel.getVisibility() == View.VISIBLE && infoListAdapter.getItemsList().size() > 0 && !isLoading.get()) {
|
||||
if (suggestionsPanel.getVisibility() == View.VISIBLE
|
||||
&& infoListAdapter.getItemsList().size() > 0
|
||||
&& !isLoading.get()) {
|
||||
hideSuggestionsPanel();
|
||||
hideKeyboardSearch();
|
||||
searchEditText.setText(lastSearchedQuery);
|
||||
searchEditText.setText(lastSearchedString);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -573,8 +601,10 @@ public class SearchFragment
|
||||
|
||||
final Observable<String> observable = suggestionPublisher
|
||||
.debounce(SUGGESTIONS_DEBOUNCE, TimeUnit.MILLISECONDS)
|
||||
.startWith(searchQuery != null ? searchQuery : "")
|
||||
.filter(query -> isSuggestionsEnabled);
|
||||
.startWith(searchString != null
|
||||
? searchString
|
||||
: "")
|
||||
.filter(searchString -> isSuggestionsEnabled);
|
||||
|
||||
suggestionDisposable = observable
|
||||
.switchMap(query -> {
|
||||
@ -645,56 +675,44 @@ public class SearchFragment
|
||||
// no-op
|
||||
}
|
||||
|
||||
private void search(final String query) {
|
||||
if (DEBUG) Log.d(TAG, "search() called with: query = [" + query + "]");
|
||||
if (query.isEmpty()) return;
|
||||
private void search(final String searchString, String[] contentFilter, String sortFilter) {
|
||||
if (DEBUG) Log.d(TAG, "search() called with: query = [" + searchString + "]");
|
||||
if (searchString.isEmpty()) return;
|
||||
|
||||
try {
|
||||
final StreamingService service = NewPipe.getServiceByUrl(query);
|
||||
final StreamingService service = NewPipe.getServiceByUrl(searchString);
|
||||
if (service != null) {
|
||||
showLoading();
|
||||
disposables.add(Observable
|
||||
.fromCallable(new Callable<Intent>() {
|
||||
@Override
|
||||
public Intent call() throws Exception {
|
||||
return NavigationHelper.getIntentByLink(activity, service, query);
|
||||
}
|
||||
})
|
||||
.fromCallable(() ->
|
||||
NavigationHelper.getIntentByLink(activity, service, searchString))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Consumer<Intent>() {
|
||||
@Override
|
||||
public void accept(Intent intent) throws Exception {
|
||||
getFragmentManager().popBackStackImmediate();
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}, new Consumer<Throwable>() {
|
||||
@Override
|
||||
public void accept(Throwable throwable) throws Exception {
|
||||
showError(getString(R.string.url_not_supported_toast), false);
|
||||
}
|
||||
}));
|
||||
.subscribe(intent -> {
|
||||
getFragmentManager().popBackStackImmediate();
|
||||
activity.startActivity(intent);
|
||||
}, throwable ->
|
||||
showError(getString(R.string.url_not_supported_toast), false)));
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Exception occurred, it's not a url
|
||||
}
|
||||
|
||||
lastSearchedQuery = query;
|
||||
searchQuery = query;
|
||||
currentPage = 0;
|
||||
lastSearchedString = this.searchString;
|
||||
this.searchString = searchString;
|
||||
infoListAdapter.clearStreamItemList();
|
||||
hideSuggestionsPanel();
|
||||
hideKeyboardSearch();
|
||||
|
||||
historyRecordManager.onSearched(serviceId, query)
|
||||
historyRecordManager.onSearched(serviceId, searchString)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
ignored -> {},
|
||||
error -> showSnackBarError(error, UserAction.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), query, 0)
|
||||
NewPipe.getNameOfService(serviceId), searchString, 0)
|
||||
);
|
||||
suggestionPublisher.onNext(query);
|
||||
suggestionPublisher.onNext(searchString);
|
||||
startLoading(false);
|
||||
}
|
||||
|
||||
@ -703,11 +721,16 @@ public class SearchFragment
|
||||
super.startLoading(forceLoad);
|
||||
if (disposables != null) disposables.clear();
|
||||
if (searchDisposable != null) searchDisposable.dispose();
|
||||
searchDisposable = ExtractorHelper.searchFor(serviceId, searchQuery, currentPage, contentCountry, filter)
|
||||
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
||||
searchString,
|
||||
Arrays.asList(contentFilter),
|
||||
sortFilter,
|
||||
contentCountry)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
||||
.subscribe(this::handleResult, this::onError);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -715,8 +738,13 @@ public class SearchFragment
|
||||
isLoading.set(true);
|
||||
showListFooter(true);
|
||||
if (searchDisposable != null) searchDisposable.dispose();
|
||||
currentNextPage = currentPage + 1;
|
||||
searchDisposable = ExtractorHelper.getMoreSearchItems(serviceId, searchQuery, currentNextPage, contentCountry, filter)
|
||||
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
||||
serviceId,
|
||||
searchString,
|
||||
asList(contentFilter),
|
||||
sortFilter,
|
||||
nextPageUrl,
|
||||
contentCountry)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
|
||||
@ -739,19 +767,22 @@ public class SearchFragment
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void changeFilter(MenuItem item, SearchEngine.Filter filter) {
|
||||
this.filter = filter;
|
||||
private void changeContentFilter(MenuItem item, List<String> contentFilter) {
|
||||
this.filterItemCheckedId = item.getItemId();
|
||||
item.setChecked(true);
|
||||
|
||||
if (!TextUtils.isEmpty(searchQuery)) {
|
||||
search(searchQuery);
|
||||
this.contentFilter = new String[] {contentFilter.get(0)};
|
||||
|
||||
if (!TextUtils.isEmpty(searchString)) {
|
||||
search(searchString, this.contentFilter, sortFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void setQuery(int serviceId, String searchQuery) {
|
||||
private void setQuery(int serviceId, String searchString, String[] contentfilter, String sortFilter) {
|
||||
this.serviceId = serviceId;
|
||||
this.searchQuery = searchQuery;
|
||||
this.searchString = searchString;
|
||||
this.contentFilter = contentfilter;
|
||||
this.sortFilter = sortFilter;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -772,8 +803,11 @@ public class SearchFragment
|
||||
if (DEBUG) Log.d(TAG, "onSuggestionError() called with: exception = [" + exception + "]");
|
||||
if (super.onError(exception)) return;
|
||||
|
||||
int errorId = exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.GET_SUGGESTIONS, NewPipe.getNameOfService(serviceId), searchQuery, errorId);
|
||||
int errorId = exception instanceof ParsingException
|
||||
? R.string.parsing_error
|
||||
: R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.GET_SUGGESTIONS,
|
||||
NewPipe.getNameOfService(serviceId), searchString, errorId);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -798,16 +832,19 @@ public class SearchFragment
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void handleResult(@NonNull SearchResult result) {
|
||||
if (!result.errors.isEmpty()) {
|
||||
showSnackBarError(result.errors, UserAction.SEARCHED, NewPipe.getNameOfService(serviceId), searchQuery, 0);
|
||||
public void handleResult(@NonNull SearchInfo result) {
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), searchString, 0);
|
||||
}
|
||||
|
||||
lastSearchedQuery = searchQuery;
|
||||
lastSearchedString = searchString;
|
||||
nextPageUrl = result.getNextPageUrl();
|
||||
currentPageUrl = result.getUrl();
|
||||
|
||||
if (infoListAdapter.getItemsList().size() == 0) {
|
||||
if (!result.getResults().isEmpty()) {
|
||||
infoListAdapter.addInfoItemList(result.getResults());
|
||||
if (!result.getRelatedItems().isEmpty()) {
|
||||
infoListAdapter.addInfoItemList(result.getRelatedItems());
|
||||
} else {
|
||||
infoListAdapter.clearStreamItemList();
|
||||
showEmptyState();
|
||||
@ -821,12 +858,13 @@ public class SearchFragment
|
||||
@Override
|
||||
public void handleNextItems(ListExtractor.InfoItemsPage result) {
|
||||
showListFooter(false);
|
||||
currentPage = Integer.parseInt(result.getNextPageUrl());
|
||||
currentPageUrl = result.getNextPageUrl();
|
||||
infoListAdapter.addInfoItemList(result.getItems());
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.SEARCHED, NewPipe.getNameOfService(serviceId)
|
||||
, "\"" + searchQuery + "\" → page " + currentPage, 0);
|
||||
showSnackBarError(result.getErrors(), UserAction.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId)
|
||||
, "\"" + searchString + "\" → page: " + nextPageUrl, 0);
|
||||
}
|
||||
super.handleNextItems(result);
|
||||
}
|
||||
@ -835,12 +873,15 @@ public class SearchFragment
|
||||
protected boolean onError(Throwable exception) {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
if (exception instanceof SearchEngine.NothingFoundException) {
|
||||
if (exception instanceof SearchExtractor.NothingFoundException) {
|
||||
infoListAdapter.clearStreamItemList();
|
||||
showEmptyState();
|
||||
} else {
|
||||
int errorId = exception instanceof ParsingException ? R.string.parsing_error : R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.SEARCHED, NewPipe.getNameOfService(serviceId), searchQuery, errorId);
|
||||
int errorId = exception instanceof ParsingException
|
||||
? R.string.parsing_error
|
||||
: R.string.general_error;
|
||||
onUnrecoverableError(exception, UserAction.SEARCHED,
|
||||
NewPipe.getNameOfService(serviceId), searchString, errorId);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -6,6 +6,7 @@ import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -19,9 +20,11 @@ import org.schabi.newpipe.database.LocalItem;
|
||||
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.local.BaseLocalListFragment;
|
||||
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||
import org.schabi.newpipe.local.playlist.RemotePlaylistManager;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.OnClickGesture;
|
||||
@ -99,19 +102,26 @@ public final class BookmarkFragment
|
||||
itemListAdapter.setSelectedListener(new OnClickGesture<LocalItem>() {
|
||||
@Override
|
||||
public void selected(LocalItem selectedItem) {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
if (getParentFragment() == null) return;
|
||||
final FragmentManager fragmentManager = getParentFragment().getFragmentManager();
|
||||
try {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
if (getParentFragment() == null) return;
|
||||
final FragmentManager fragmentManager = getParentFragment().getFragmentManager();
|
||||
|
||||
if (selectedItem instanceof PlaylistMetadataEntry) {
|
||||
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
|
||||
NavigationHelper.openLocalPlaylistFragment(fragmentManager, entry.uid,
|
||||
entry.name);
|
||||
if (selectedItem instanceof PlaylistMetadataEntry) {
|
||||
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
|
||||
NavigationHelper.openLocalPlaylistFragment(fragmentManager, entry.uid,
|
||||
entry.name);
|
||||
|
||||
} else if (selectedItem instanceof PlaylistRemoteEntity) {
|
||||
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
|
||||
NavigationHelper.openPlaylistFragment(fragmentManager, entry.getServiceId(),
|
||||
entry.getUrl(), entry.getName());
|
||||
} else if (selectedItem instanceof PlaylistRemoteEntity) {
|
||||
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
|
||||
NavigationHelper.openPlaylistFragment(
|
||||
fragmentManager,
|
||||
entry.getServiceId(),
|
||||
entry.getUrl(),
|
||||
entry.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
@ -38,6 +39,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
|
||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsExportService;
|
||||
import org.schabi.newpipe.local.subscription.services.SubscriptionsImportService;
|
||||
@ -318,9 +320,15 @@ public class SubscriptionFragment extends BaseStateFragment<List<SubscriptionEnt
|
||||
infoListAdapter.setOnChannelSelectedListener(new OnClickGesture<ChannelInfoItem>() {
|
||||
@Override
|
||||
public void selected(ChannelInfoItem selectedItem) {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(),
|
||||
selectedItem.getServiceId(), selectedItem.getUrl(), selectedItem.getName());
|
||||
try {
|
||||
// Requires the parent fragment to find holder for fragment replacement
|
||||
NavigationHelper.openChannelFragment(getParentFragment().getFragmentManager(),
|
||||
selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -6,7 +6,7 @@ public class Constants {
|
||||
public static final String KEY_TITLE = "key_title";
|
||||
public static final String KEY_LINK_TYPE = "key_link_type";
|
||||
public static final String KEY_OPEN_SEARCH = "key_open_search";
|
||||
public static final String KEY_QUERY = "key_query";
|
||||
public static final String KEY_SEARCH_STRING = "key_search_string";
|
||||
|
||||
public static final String KEY_THEME_CHANGE = "key_theme_change";
|
||||
public static final String KEY_MAIN_PAGE_CHANGE = "key_main_page_change";
|
||||
|
@ -37,9 +37,8 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.search.SearchInfo;
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
@ -50,7 +49,6 @@ import java.util.List;
|
||||
|
||||
import io.reactivex.Maybe;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.annotations.NonNull;
|
||||
|
||||
public final class ExtractorHelper {
|
||||
private static final String TAG = ExtractorHelper.class.getSimpleName();
|
||||
@ -66,29 +64,35 @@ 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<SearchInfo> searchFor(final int serviceId,
|
||||
final String searchString,
|
||||
final List<String> contentFilter,
|
||||
final String sortFilter,
|
||||
final String contentCountry) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(() ->
|
||||
SearchResult.getSearchResult(NewPipe.getService(serviceId).getSearchEngine(),
|
||||
query, pageNumber, contentCountry, filter)
|
||||
);
|
||||
SearchInfo.getInfo(NewPipe.getService(serviceId),
|
||||
NewPipe.getService(serviceId)
|
||||
.getSearchQIHFactory()
|
||||
.fromQuery(searchString, contentFilter, sortFilter),
|
||||
contentCountry));
|
||||
}
|
||||
|
||||
public static Single<InfoItemsPage> getMoreSearchItems(final int serviceId,
|
||||
final String query,
|
||||
final int nextPageNumber,
|
||||
final String searchLanguage,
|
||||
final SearchEngine.Filter filter) {
|
||||
final String searchString,
|
||||
final List<String> contentFilter,
|
||||
final String sortFilter,
|
||||
final String pageUrl,
|
||||
final String contentCountry) {
|
||||
checkServiceId(serviceId);
|
||||
return searchFor(serviceId, query, nextPageNumber, searchLanguage, filter)
|
||||
.map((@NonNull SearchResult searchResult) ->
|
||||
new InfoItemsPage(searchResult.resultList,
|
||||
nextPageNumber + "",
|
||||
searchResult.errors));
|
||||
return Single.fromCallable(() ->
|
||||
SearchInfo.getMoreItems(NewPipe.getService(serviceId),
|
||||
NewPipe.getService(serviceId)
|
||||
.getSearchQIHFactory()
|
||||
.fromQuery(searchString, contentFilter, sortFilter),
|
||||
contentCountry,
|
||||
pageUrl));
|
||||
|
||||
}
|
||||
|
||||
public static Single<List<String>> suggestionsFor(final int serviceId,
|
||||
@ -233,7 +237,6 @@ public final class ExtractorHelper {
|
||||
serviceId == -1 ? "none" : NewPipe.getNameOfService(serviceId), url + (optionalErrorMessage == null ? "" : optionalErrorMessage), errorId));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,10 +26,13 @@ import org.schabi.newpipe.download.DownloadActivity;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.Stream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
|
||||
import org.schabi.newpipe.fragments.MainFragment;
|
||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
||||
@ -283,9 +286,11 @@ public class NavigationHelper {
|
||||
return fragmentManager.popBackStackImmediate(SEARCH_FRAGMENT_TAG, 0);
|
||||
}
|
||||
|
||||
public static void openSearchFragment(FragmentManager fragmentManager, int serviceId, String query) {
|
||||
public static void openSearchFragment(FragmentManager fragmentManager,
|
||||
int serviceId,
|
||||
String searchString) {
|
||||
defaultTransaction(fragmentManager)
|
||||
.replace(R.id.fragment_holder, SearchFragment.getInstance(serviceId, query))
|
||||
.replace(R.id.fragment_holder, SearchFragment.getInstance(serviceId, searchString))
|
||||
.addToBackStack(SEARCH_FRAGMENT_TAG)
|
||||
.commit();
|
||||
}
|
||||
@ -314,7 +319,11 @@ public class NavigationHelper {
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void openChannelFragment(FragmentManager fragmentManager, int serviceId, String url, String name) {
|
||||
public static void openChannelFragment(
|
||||
FragmentManager fragmentManager,
|
||||
int serviceId,
|
||||
String url,
|
||||
String name) {
|
||||
if (name == null) name = "";
|
||||
defaultTransaction(fragmentManager)
|
||||
.replace(R.id.fragment_holder, ChannelFragment.getInstance(serviceId, url, name))
|
||||
@ -322,7 +331,10 @@ public class NavigationHelper {
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void openPlaylistFragment(FragmentManager fragmentManager, int serviceId, String url, String name) {
|
||||
public static void openPlaylistFragment(FragmentManager fragmentManager,
|
||||
int serviceId,
|
||||
String url,
|
||||
String name) {
|
||||
if (name == null) name = "";
|
||||
defaultTransaction(fragmentManager)
|
||||
.replace(R.id.fragment_holder, PlaylistFragment.getInstance(serviceId, url, name))
|
||||
@ -370,10 +382,10 @@ public class NavigationHelper {
|
||||
// Through Intents
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public static void openSearch(Context context, int serviceId, String query) {
|
||||
public static void openSearch(Context context, int serviceId, String searchString) {
|
||||
Intent mIntent = new Intent(context, MainActivity.class);
|
||||
mIntent.putExtra(Constants.KEY_SERVICE_ID, serviceId);
|
||||
mIntent.putExtra(Constants.KEY_QUERY, query);
|
||||
mIntent.putExtra(Constants.KEY_SEARCH_STRING, searchString);
|
||||
mIntent.putExtra(Constants.KEY_OPEN_SEARCH, true);
|
||||
context.startActivity(mIntent);
|
||||
}
|
||||
@ -467,7 +479,8 @@ public class NavigationHelper {
|
||||
|
||||
switch (linkType) {
|
||||
case STREAM:
|
||||
rIntent.putExtra(VideoDetailFragment.AUTO_PLAY, PreferenceManager.getDefaultSharedPreferences(context)
|
||||
rIntent.putExtra(VideoDetailFragment.AUTO_PLAY,
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.getBoolean(context.getString(R.string.autoplay_through_intent_key), false));
|
||||
break;
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import android.preference.PreferenceManager;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.StringRes;
|
||||
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
@ -31,6 +30,18 @@ public class ServiceHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public static String getTranslatedFilterString(String filter, Context c) {
|
||||
switch(filter) {
|
||||
case "all": return c.getString(R.string.all);
|
||||
case "videos": return c.getString(R.string.videos);
|
||||
case "channels": return c.getString(R.string.channels);
|
||||
case "playlists": return c.getString(R.string.playlists);
|
||||
case "tracks": return c.getString(R.string.tracks);
|
||||
case "users": return c.getString(R.string.users);
|
||||
default: return filter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a resource string with instructions for importing subscriptions for each service.
|
||||
*
|
||||
|
@ -125,7 +125,12 @@
|
||||
<string name="error_report_title">Error report</string>
|
||||
<string name="all">All</string>
|
||||
<string name="channel">Channel</string>
|
||||
<string name="channels">Channels</string>
|
||||
<string name="playlist">Playlist</string>
|
||||
<string name="playlists">Playlists</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="tracks">Tracks</string>
|
||||
<string name="users">Users</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="later">Later</string>
|
||||
<string name="disabled">Disabled</string>
|
||||
|
@ -6,7 +6,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
Loading…
Reference in New Issue
Block a user