Merge branch 'feature-improve-search-fragment' of git://github.com/coffeemakr/NewPipe into cofe

This commit is contained in:
Christian Schabesberger 2017-01-22 14:42:36 +01:00
commit 7d6b92e064
15 changed files with 122 additions and 105 deletions

View File

@ -51,8 +51,6 @@ public class MainActivity extends ThemableActivity {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
mainFragment.onCreateOptionsMenu(menu, inflater);
return true;
}
@ -81,8 +79,7 @@ public class MainActivity extends ThemableActivity {
return true;
}
default:
return mainFragment.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
}
}

View File

@ -164,19 +164,10 @@ public class VideoItemDetailActivity extends ThemableActivity {
NavUtils.navigateUpTo(this, intent);
return true;
} else {
return fragment.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
fragment.onCreateOptionsMenu(menu, getMenuInflater());
return true;
}
/**
* Retrieves all Strings which look remotely like URLs from a text.
* Used if NewPipe was called through share menu.

View File

@ -633,6 +633,7 @@ public class VideoItemDetailFragment extends Fragment {
onNotSpecifiedContentError();
}
});
setHasOptionsMenu(true);
}
@Override

View File

@ -261,8 +261,7 @@ public class DownloadActivity extends ThemableActivity implements AdapterView.On
return true;
}
default:
return mFragment.onOptionsItemSelected(item) ||
super.onOptionsItemSelected(item);
return super.onOptionsItemSelected(item);
}
}

View File

@ -4,7 +4,6 @@ import org.schabi.newpipe.extractor.UrlIdHandler;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import java.io.IOException;
import java.util.List;
/**
* Created by Christian Schabesberger on 10.08.15.
@ -26,7 +25,6 @@ import java.util.List;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
@SuppressWarnings("ALL")
public abstract class SearchEngine {
public static class NothingFoundException extends ExtractionException {
public NothingFoundException(String message) {

View File

@ -85,18 +85,18 @@ public class YoutubeSearchEngine extends SearchEngine {
Element el;
// both types of spell correction item
if (!((el = item.select("div[class*=\"spell-correction\"]").first()) == null)) {
if ((el = item.select("div[class*=\"spell-correction\"]").first()) != null) {
collector.setSuggestion(el.select("a").first().text());
if(list.children().size() == 1) {
throw new NothingFoundException("Did you mean: " + el.select("a").first().text());
}
// search message item
} else if (!((el = item.select("div[class*=\"search-message\"]").first()) == null)) {
} else if ((el = item.select("div[class*=\"search-message\"]").first()) != null) {
//result.errorMessage = el.text();
throw new NothingFoundException(el.text());
// video item type
} else if (!((el = item.select("div[class*=\"yt-lockup-video\"").first()) == null)) {
} else if ((el = item.select("div[class*=\"yt-lockup-video\"").first()) != null) {
collector.commit(extractPreviewInfo(el));
} else {
//noinspection ConstantConditions

View File

@ -30,13 +30,13 @@ import org.schabi.newpipe.R;
public class InfoItemHolder extends RecyclerView.ViewHolder {
public ImageView itemThumbnailView;
public TextView itemVideoTitleView,
public final ImageView itemThumbnailView;
public final TextView itemVideoTitleView,
itemUploaderView,
itemDurationView,
itemUploadDateView,
itemViewCountView;
public Button itemButton;
public final Button itemButton;
public InfoItemHolder(View v) {
super(v);

View File

@ -34,11 +34,12 @@ import java.util.Vector;
public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
InfoItemBuilder infoItemBuilder = null;
List<StreamPreviewInfo> streamList = new Vector<>();
private final InfoItemBuilder infoItemBuilder;
private final List<StreamPreviewInfo> streamList;
public InfoListAdapter(Activity a, View rootView) {
infoItemBuilder = new InfoItemBuilder(a, rootView);
streamList = new Vector<>();
}
public void setOnItemSelectedListener
@ -54,7 +55,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
}
public void clearSteamItemList() {
streamList = new Vector<>();
streamList.clear();
notifyDataSetChanged();
}

View File

@ -56,13 +56,15 @@ public class SearchInfoItemFragment extends Fragment {
private static final String TAG = SearchInfoItemFragment.class.toString();
/**
* Listener for search queries
*/
public class SearchQueryListener implements SearchView.OnQueryTextListener {
@Override
public boolean onQueryTextSubmit(String query) {
Activity a = getActivity();
try {
searchQuery = query;
search(query);
// hide virtual keyboard
@ -89,8 +91,6 @@ public class SearchInfoItemFragment extends Fragment {
} catch (Exception e) {
e.printStackTrace();
}
View bg = a.findViewById(R.id.mainBG);
bg.setVisibility(View.GONE);
return true;
}
@ -108,12 +108,10 @@ public class SearchInfoItemFragment extends Fragment {
private boolean isLoading = false;
private ProgressBar loadingIndicator = null;
private SearchView searchView = null;
private int pageNumber = 0;
private SuggestionListAdapter suggestionListAdapter = null;
private InfoListAdapter infoListAdapter = null;
private LinearLayoutManager streamInfoListLayoutManager = null;
private RecyclerView recyclerView = null;
// savedInstanceBundle arguments
private static final String QUERY = "query";
@ -126,23 +124,32 @@ public class SearchInfoItemFragment extends Fragment {
public SearchInfoItemFragment() {
}
// TODO: Customize parameter initialization
@SuppressWarnings("unused")
public static SearchInfoItemFragment newInstance(int columnCount) {
public static SearchInfoItemFragment newInstance(int streamingServiceId, String searchQuery) {
Bundle args = new Bundle();
args.putInt(STREAMING_SERVICE, streamingServiceId);
args.putString(QUERY, searchQuery);
SearchInfoItemFragment fragment = new SearchInfoItemFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
searchQuery = "";
if (savedInstanceState != null) {
searchQuery = savedInstanceState.getString(QUERY);
streamingServiceId = savedInstanceState.getInt(STREAMING_SERVICE);
} else {
try {
Bundle args = getArguments();
if(args != null) {
searchQuery = args.getString(QUERY);
streamingServiceId = args.getInt(STREAMING_SERVICE);
} else {
streamingServiceId = NewPipe.getIdOfService("Youtube");
}
} catch (Exception e) {
e.printStackTrace();
ErrorActivity.reportError(getActivity(), e, null,
@ -153,13 +160,14 @@ public class SearchInfoItemFragment extends Fragment {
}
}
setHasOptionsMenu(true);
SearchWorker sw = SearchWorker.getInstance();
sw.setSearchWorkerResultListener(new SearchWorker.SearchWorkerResultListener() {
@Override
public void onResult(SearchResult result) {
infoListAdapter.addStreamItemList(result.resultList);
isLoading = false;
loadingIndicator.setVisibility(View.GONE);
setDoneLoading();
}
@Override
@ -167,8 +175,7 @@ public class SearchInfoItemFragment extends Fragment {
//setListShown(true);
Toast.makeText(getActivity(), getString(stringResource),
Toast.LENGTH_SHORT).show();
isLoading = false;
loadingIndicator.setVisibility(View.GONE);
setDoneLoading();
}
@Override
@ -176,8 +183,7 @@ public class SearchInfoItemFragment extends Fragment {
//setListShown(true);
Toast.makeText(getActivity(), message,
Toast.LENGTH_LONG).show();
isLoading = false;
loadingIndicator.setVisibility(View.GONE);
setDoneLoading();
}
@Override
@ -191,6 +197,7 @@ public class SearchInfoItemFragment extends Fragment {
RECAPTCHA_REQUEST);
}
});
}
@Override
@ -200,7 +207,7 @@ public class SearchInfoItemFragment extends Fragment {
Context context = view.getContext();
loadingIndicator = (ProgressBar) view.findViewById(R.id.progressBar);
recyclerView = (RecyclerView) view.findViewById(R.id.list);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.list);
streamInfoListLayoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(streamInfoListLayoutManager);
@ -209,15 +216,12 @@ public class SearchInfoItemFragment extends Fragment {
infoListAdapter.setOnItemSelectedListener(new InfoItemBuilder.OnItemSelectedListener() {
@Override
public void selected(String url) {
Intent i = new Intent(getActivity(), VideoItemDetailActivity.class);
i.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId);
i.putExtra(VideoItemDetailFragment.VIDEO_URL, url);
getActivity().startActivity(i);
startDetailActivity(url);
}
});
recyclerView.setAdapter(infoListAdapter);
recyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
recyclerView.clearOnScrollListeners();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int pastVisiblesItems, visibleItemCount, totalItemCount;
@ -239,14 +243,26 @@ public class SearchInfoItemFragment extends Fragment {
return view;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
private void startDetailActivity(String url) {
Intent i = new Intent(getActivity(), VideoItemDetailActivity.class);
i.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId);
i.putExtra(VideoItemDetailFragment.VIDEO_URL, url);
getActivity().startActivity(i);
}
@Override
public void onDetach() {
super.onDetach();
public void onStart() {
super.onStart();
if(!searchQuery.isEmpty()) {
search(searchQuery);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(QUERY, searchQuery);
outState.putInt(STREAMING_SERVICE, streamingServiceId);
}
@Override
@ -255,15 +271,10 @@ public class SearchInfoItemFragment extends Fragment {
inflater.inflate(R.menu.search_menu, menu);
MenuItem searchItem = menu.findItem(R.id.action_search);
searchView = (SearchView) searchItem.getActionView();
SearchView searchView = (SearchView) searchItem.getActionView();
setupSearchView(searchView);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
private void setupSearchView(SearchView searchView) {
suggestionListAdapter = new SuggestionListAdapter(getActivity());
searchView.setSuggestionsAdapter(suggestionListAdapter);
@ -278,7 +289,9 @@ public class SearchInfoItemFragment extends Fragment {
private void search(String query) {
infoListAdapter.clearSteamItemList();
pageNumber = 0;
searchQuery = query;
search(query, pageNumber);
hideBackground();
loadingIndicator.setVisibility(View.VISIBLE);
}
@ -288,6 +301,20 @@ public class SearchInfoItemFragment extends Fragment {
sw.search(streamingServiceId, query, page, getActivity());
}
private void setDoneLoading() {
this.isLoading = false;
loadingIndicator.setVisibility(View.GONE);
}
/**
* Hides the "dummy" background when no results are shown
*/
private void hideBackground() {
View view = getView();
if(view == null) return;
view.findViewById(R.id.mainBG).setVisibility(View.GONE);
}
private void searchSuggestions(String query) {
SuggestionSearchRunnable suggestionSearchRunnable =
new SuggestionSearchRunnable(streamingServiceId, query, getActivity(), suggestionListAdapter);

View File

@ -25,8 +25,8 @@ import android.support.v7.widget.SearchView;
public class SearchSuggestionListener implements SearchView.OnSuggestionListener{
private SearchView searchView;
private SuggestionListAdapter adapter;
private final SearchView searchView;
private final SuggestionListAdapter adapter;
public SearchSuggestionListener(SearchView searchView, SuggestionListAdapter adapter) {
this.searchView = searchView;

View File

@ -82,6 +82,7 @@ public class SearchWorker {
}
@Override
public void run() {
final String serviceName = NewPipe.getNameOfService(serviceId);
SearchResult result = null;
SearchEngine engine = null;
@ -119,7 +120,7 @@ public class SearchWorker {
View rootView = a.findViewById(android.R.id.content);
ErrorActivity.reportError(h, a, result.errors, null, rootView,
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
/* todo: this shoudl not be assigned static */ YOUTUBE, query, R.string.light_parsing_error));
serviceName, query, R.string.light_parsing_error));
}
// hard errors:
@ -148,8 +149,7 @@ public class SearchWorker {
} catch(ExtractionException e) {
ErrorActivity.reportError(h, a, e, null, null,
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,
/* todo: this shoudl not be assigned static */
YOUTUBE, query, R.string.parsing_error));
serviceName, query, R.string.parsing_error));
//postNewErrorToast(h, R.string.parsing_error);
e.printStackTrace();

View File

@ -3,10 +3,8 @@ package org.schabi.newpipe.search_fragment;
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.support.v4.widget.ResourceCursorAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;
@ -31,52 +29,56 @@ import java.util.List;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class SuggestionListAdapter extends CursorAdapter {
/**
* {@link ResourceCursorAdapter} to display suggestions.
*/
public class SuggestionListAdapter extends ResourceCursorAdapter {
private static final String[] columns = new String[]{"_id", "title"};
private static final int INDEX_ID = 0;
private static final int INDEX_TITLE = 1;
private String[] columns = new String[]{"_id", "title"};
public SuggestionListAdapter(Context context) {
super(context, null, false);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
ViewHolder viewHolder;
View view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
viewHolder = new ViewHolder();
viewHolder.suggestionTitle = (TextView) view.findViewById(android.R.id.text1);
view.setTag(viewHolder);
return view;
super(context, android.R.layout.simple_list_item_1, null, 0);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
viewHolder.suggestionTitle.setText(cursor.getString(1));
ViewHolder viewHolder = new ViewHolder(view);
viewHolder.suggestionTitle.setText(cursor.getString(INDEX_TITLE));
}
/**
* Update the suggestion list
* @param suggestions the list of suggestions
*/
public void updateAdapter(List<String> suggestions) {
MatrixCursor cursor = new MatrixCursor(columns);
MatrixCursor cursor = new MatrixCursor(columns, suggestions.size());
int i = 0;
for (String s : suggestions) {
String[] temp = new String[2];
temp[0] = Integer.toString(i);
temp[1] = s;
for (String suggestion : suggestions) {
String[] columnValues = new String[columns.length];
columnValues[INDEX_TITLE] = suggestion;
columnValues[INDEX_ID] = Integer.toString(i);
cursor.addRow(columnValues);
i++;
cursor.addRow(temp);
}
changeCursor(cursor);
}
/**
* Get the suggestion for a position
* @param position the position of the suggestion
* @return the suggestion
*/
public String getSuggestion(int position) {
return ((Cursor) getItem(position)).getString(1);
return ((Cursor) getItem(position)).getString(INDEX_TITLE);
}
private class ViewHolder {
public TextView suggestionTitle;
private final TextView suggestionTitle;
private ViewHolder(View view) {
this.suggestionTitle = (TextView) view.findViewById(android.R.id.text1);
}
}
}

View File

@ -37,14 +37,15 @@ import java.util.List;
public class SuggestionSearchRunnable implements Runnable{
/**
* Runnable to update a {@link SuggestionListAdapter}
*/
private class SuggestionResultRunnable implements Runnable{
private List<String> suggestions;
private SuggestionListAdapter adapter;
private final List<String> suggestions;
private SuggestionResultRunnable(List<String> suggestions, SuggestionListAdapter adapter) {
private SuggestionResultRunnable(List<String> suggestions) {
this.suggestions = suggestions;
this.adapter = adapter;
}
@Override
@ -55,9 +56,9 @@ public class SuggestionSearchRunnable implements Runnable{
private final int serviceId;
private final String query;
final Handler h = new Handler();
private Activity a = null;
private SuggestionListAdapter adapter;
private final Handler h = new Handler();
private final Activity a;
private final SuggestionListAdapter adapter;
public SuggestionSearchRunnable(int serviceId, String query,
Activity activity, SuggestionListAdapter adapter) {
this.serviceId = serviceId;
@ -76,7 +77,7 @@ public class SuggestionSearchRunnable implements Runnable{
String searchLanguage = sp.getString(searchLanguageKey,
a.getString(R.string.default_language_value));
List<String> suggestions = se.suggestionList(query, searchLanguage);
h.post(new SuggestionResultRunnable(suggestions, adapter));
h.post(new SuggestionResultRunnable(suggestions));
} catch (ExtractionException e) {
ErrorActivity.reportError(h, a, e, null, a.findViewById(android.R.id.content),
ErrorActivity.ErrorInfo.make(ErrorActivity.SEARCHED,

View File

@ -6,8 +6,6 @@
tools:context="org.schabi.newpipe.MainActivity"
android:orientation="vertical">
<include layout="@layout/main_bg" />
<fragment
android:id="@+id/search_fragment"
android:name="org.schabi.newpipe.search_fragment.SearchInfoItemFragment"

View File

@ -7,6 +7,8 @@
android:name="org.schabi.newpipe.SearchInfoItemFragment"
tools:context=".search_fragment.SearchInfoItemFragment">
<include layout="@layout/main_bg" />
<android.support.v7.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"