From b865326d516b8f73984fbecfe14d5b91cd425a5a Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Mon, 2 Nov 2015 19:57:47 +0100 Subject: [PATCH 1/3] added ability to show similar videos --- app/build.gradle | 2 +- .../org/schabi/newpipe/ActionBarHandler.java | 3 +- .../java/org/schabi/newpipe/VideoInfo.java | 2 +- .../org/schabi/newpipe/VideoInfoItem.java | 51 ++++++++++- .../newpipe/VideoItemDetailActivity.java | 1 - .../newpipe/VideoItemDetailFragment.java | 84 ++++++++++++------- .../schabi/newpipe/VideoItemListActivity.java | 77 +++++++++++++---- .../schabi/newpipe/VideoItemListFragment.java | 25 +++++- .../newpipe/youtube/YoutubeExtractor.java | 18 ++-- .../layout-land/fragment_videoitem_detail.xml | 10 ++- .../fragment_videoitem_detail.xml | 10 ++- .../res/layout/fragment_videoitem_detail.xml | 11 ++- app/src/main/res/values-de/strings.xml | 3 +- app/src/main/res/values/strings.xml | 1 + 14 files changed, 225 insertions(+), 73 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 657b85604..5e17108de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,7 +23,7 @@ dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'com.android.support:appcompat-v7:23.1.0' compile 'com.android.support:support-v4:23.1.0' + compile 'com.android.support:design:23.1.0' compile 'org.jsoup:jsoup:1.8.3' compile 'org.mozilla:rhino:1.7.7' - compile 'com.android.support:design:23.1.0' } diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index 6c8d73696..36c6772c8 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -69,6 +69,7 @@ public class ActionBarHandler { public void setStreams(VideoInfo.VideoStream[] videoStreams, VideoInfo.AudioStream[] audioStreams) { this.videoStreams = videoStreams; selectedStream = 0; + defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity); String[] itemArray = new String[videoStreams.length]; String defaultResolution = defaultPreferences .getString(activity.getString(R.string.defaultResolutionPreference), @@ -93,7 +94,7 @@ public class ActionBarHandler { // set audioStream audioStream = null; - String preferedFormat = PreferenceManager.getDefaultSharedPreferences(activity) + String preferedFormat = defaultPreferences .getString(activity.getString(R.string.defaultAudioFormatPreference), "webm"); if(preferedFormat.equals("webm")) { for(VideoInfo.AudioStream s : audioStreams) { diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfo.java b/app/src/main/java/org/schabi/newpipe/VideoInfo.java index 5181b6d8b..41f966802 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfo.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfo.java @@ -140,6 +140,6 @@ public class VideoInfo { public VideoStream[] videoStreams = null; public AudioStream[] audioStreams = null; public VideoInfoItem nextVideo = null; - public Vector relatedVideos = null; + public VideoInfoItem[] relatedVideos = null; public int videoAvailableStatus = VIDEO_AVAILABLE; } \ No newline at end of file diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java index ce7ebdd6e..e34f064b1 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItem.java @@ -1,6 +1,8 @@ package org.schabi.newpipe; import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; /** * Created by Christian Schabesberger on 26.08.15. @@ -22,7 +24,7 @@ import android.graphics.Bitmap; * along with NewPipe. If not, see . */ -public class VideoInfoItem { +public class VideoInfoItem implements Parcelable { public String id = ""; public String title = ""; public String uploader = ""; @@ -32,4 +34,51 @@ public class VideoInfoItem { public String webpage_url = ""; public String upload_date = ""; public String view_count = ""; + + protected VideoInfoItem(Parcel in) { + id = in.readString(); + title = in.readString(); + uploader = in.readString(); + duration = in.readString(); + thumbnail_url = in.readString(); + thumbnail = (Bitmap) in.readValue(Bitmap.class.getClassLoader()); + webpage_url = in.readString(); + upload_date = in.readString(); + view_count = in.readString(); + } + + public VideoInfoItem() { + + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(id); + dest.writeString(title); + dest.writeString(uploader); + dest.writeString(duration); + dest.writeString(thumbnail_url); + dest.writeValue(thumbnail); + dest.writeString(webpage_url); + dest.writeString(upload_date); + dest.writeString(view_count); + } + + @SuppressWarnings("unused") + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public VideoInfoItem createFromParcel(Parcel in) { + return new VideoInfoItem(in); + } + + @Override + public VideoInfoItem[] newArray(int size) { + return new VideoInfoItem[size]; + } + }; } \ No newline at end of file diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java index 8f4416f76..0d29a61d4 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java @@ -37,7 +37,6 @@ public class VideoItemDetailActivity extends AppCompatActivity { private String videoUrl; private int currentStreamingService = -1; - private Menu menu = null; protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index 653aed1af..0d77ed213 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -81,7 +81,7 @@ public class VideoItemDetailFragment extends Fragment { private Handler h = new Handler(); private Class extractorClass; private String videoUrl; - public ExtractorRunnable(String videoUrl, Class extractorClass, VideoItemDetailFragment f) { + public ExtractorRunnable(String videoUrl, Class extractorClass) { this.extractorClass = extractorClass; this.videoUrl = videoUrl; } @@ -96,18 +96,21 @@ public class VideoItemDetailFragment extends Fragment { BitmapFactory.decodeStream( new URL(videoInfo.thumbnail_url) .openConnection() - .getInputStream()), SetThumbnailRunnable.VIDEO_THUMBNAIL)); + .getInputStream()), + SetThumbnailRunnable.VIDEO_THUMBNAIL)); h.post(new SetThumbnailRunnable( BitmapFactory.decodeStream( new URL(videoInfo.uploader_thumbnail_url) .openConnection() - .getInputStream()), SetThumbnailRunnable.CHANNEL_THUMBNAIL)); + .getInputStream()), + SetThumbnailRunnable.CHANNEL_THUMBNAIL)); if(showNextVideoItem) { h.post(new SetThumbnailRunnable( BitmapFactory.decodeStream( new URL(videoInfo.nextVideo.thumbnail_url) .openConnection() - .getInputStream()), SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL)); + .getInputStream()), + SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL)); } } } catch (Exception e) { @@ -176,29 +179,28 @@ public class VideoItemDetailFragment extends Fragment { } public void updateInfo(VideoInfo info) { - Activity a = getActivity(); currentVideoInfo = info; try { VideoInfoItemViewCreator videoItemViewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(getActivity())); - ScrollView contentMainView = (ScrollView) a.findViewById(R.id.detailMainContent); - ProgressBar progressBar = (ProgressBar) a.findViewById(R.id.detailProgressBar); - TextView videoTitleView = (TextView) a.findViewById(R.id.detailVideoTitleView); - TextView uploaderView = (TextView) a.findViewById(R.id.detailUploaderView); - TextView viewCountView = (TextView) a.findViewById(R.id.detailViewCountView); - TextView thumbsUpView = (TextView) a.findViewById(R.id.detailThumbsUpCountView); - TextView thumbsDownView = (TextView) a.findViewById(R.id.detailThumbsDownCountView); - TextView uploadDateView = (TextView) a.findViewById(R.id.detailUploadDateView); - TextView descriptionView = (TextView) a.findViewById(R.id.detailDescriptionView); - ImageView thumbnailView = (ImageView) a.findViewById(R.id.detailThumbnailView); - FrameLayout nextVideoFrame = (FrameLayout) a.findViewById(R.id.detailNextVideoFrame); + ScrollView contentMainView = (ScrollView) activity.findViewById(R.id.detailMainContent); + ProgressBar progressBar = (ProgressBar) activity.findViewById(R.id.detailProgressBar); + TextView videoTitleView = (TextView) activity.findViewById(R.id.detailVideoTitleView); + TextView uploaderView = (TextView) activity.findViewById(R.id.detailUploaderView); + TextView viewCountView = (TextView) activity.findViewById(R.id.detailViewCountView); + TextView thumbsUpView = (TextView) activity.findViewById(R.id.detailThumbsUpCountView); + TextView thumbsDownView = (TextView) activity.findViewById(R.id.detailThumbsDownCountView); + TextView uploadDateView = (TextView) activity.findViewById(R.id.detailUploadDateView); + TextView descriptionView = (TextView) activity.findViewById(R.id.detailDescriptionView); + ImageView thumbnailView = (ImageView) activity.findViewById(R.id.detailThumbnailView); + FrameLayout nextVideoFrame = (FrameLayout) activity.findViewById(R.id.detailNextVideoFrame); RelativeLayout nextVideoRootFrame = - (RelativeLayout) a.findViewById(R.id.detailNextVideoRootLayout); + (RelativeLayout) activity.findViewById(R.id.detailNextVideoRootLayout); View nextVideoView = videoItemViewCreator .getViewByVideoInfoItem(null, nextVideoFrame, info.nextVideo); nextVideoFrame.addView(nextVideoView); - Button nextVideoButton = (Button) a.findViewById(R.id.detailNextVideoButton); + Button nextVideoButton = (Button) activity.findViewById(R.id.detailNextVideoButton); contentMainView.setVisibility(View.VISIBLE); progressBar.setVisibility(View.GONE); @@ -210,10 +212,12 @@ public class VideoItemDetailFragment extends Fragment { case VideoInfo.VIDEO_AVAILABLE: { videoTitleView.setText(info.title); uploaderView.setText(info.uploader); - viewCountView.setText(info.view_count + " " + a.getString(R.string.viewSufix)); + viewCountView.setText(info.view_count + + " " + activity.getString(R.string.viewSufix)); thumbsUpView.setText(info.like_count); thumbsDownView.setText(info.dislike_count); - uploadDateView.setText(a.getString(R.string.uploadDatePrefix) + " " + info.upload_date); + uploadDateView.setText( + activity.getString(R.string.uploadDatePrefix) + " " + info.upload_date); descriptionView.setText(Html.fromHtml(info.description)); descriptionView.setMovementMethod(LinkMovementMethod.getInstance()); @@ -236,9 +240,12 @@ public class VideoItemDetailFragment extends Fragment { nextVideoButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - Intent detailIntent = new Intent(getActivity(), VideoItemDetailActivity.class); - detailIntent.putExtra(VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); - detailIntent.putExtra(VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url); + Intent detailIntent = + new Intent(getActivity(), VideoItemDetailActivity.class); + detailIntent.putExtra( + VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); + detailIntent.putExtra( + VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url); //todo: make id dynamic the following line is crap detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, 0); startActivity(detailIntent); @@ -246,10 +253,12 @@ public class VideoItemDetailFragment extends Fragment { }); break; case VideoInfo.VIDEO_UNAVAILABLE_GEMA: - thumbnailView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.gruese_die_gema_unangebracht)); + thumbnailView.setImageBitmap(BitmapFactory.decodeResource( + getResources(), R.drawable.gruese_die_gema_unangebracht)); break; case VideoInfo.VIDEO_UNAVAILABLE: - thumbnailView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.not_available_monkey)); + thumbnailView.setImageBitmap(BitmapFactory.decodeResource( + getResources(), R.drawable.not_available_monkey)); break; default: Log.e(TAG, "Video Available Status not known."); @@ -304,15 +313,18 @@ public class VideoItemDetailFragment extends Fragment { @Override public void onActivityCreated(Bundle savedInstanceBundle) { super.onActivityCreated(savedInstanceBundle); - FloatingActionButton playVideoButton = (FloatingActionButton) getActivity().findViewById(R.id.playVideoButton); + FloatingActionButton playVideoButton = + (FloatingActionButton) getActivity().findViewById(R.id.playVideoButton); + // Sometimes when this fragment is not visible it still gets initiated + // then we must not try to access objects of this fragment. + // Otherwise the applications would crash. if(playVideoButton != null) { - try { StreamingService streamingService = ServiceList.getService( getArguments().getInt(STREAMING_SERVICE)); extractorThread = new Thread(new ExtractorRunnable( - getArguments().getString(VIDEO_URL), streamingService.getExtractorClass(), this)); + getArguments().getString(VIDEO_URL), streamingService.getExtractorClass())); autoPlayEnabled = getArguments().getBoolean(AUTO_PLAY); extractorThread.start(); } catch (Exception e) { @@ -321,13 +333,15 @@ public class VideoItemDetailFragment extends Fragment { if (PreferenceManager.getDefaultSharedPreferences(getActivity()) .getBoolean(getString(R.string.leftHandLayout), false) && checkIfLandscape()) { - RelativeLayout.LayoutParams oldLayout = (RelativeLayout.LayoutParams) playVideoButton.getLayoutParams(); + RelativeLayout.LayoutParams oldLayout = + (RelativeLayout.LayoutParams) playVideoButton.getLayoutParams(); RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); - layoutParams.setMargins(oldLayout.leftMargin, oldLayout.topMargin, oldLayout.rightMargin, oldLayout.bottomMargin); + layoutParams.setMargins(oldLayout.leftMargin, oldLayout.topMargin, + oldLayout.rightMargin, oldLayout.bottomMargin); playVideoButton.setLayoutParams(layoutParams); } @@ -337,6 +351,16 @@ public class VideoItemDetailFragment extends Fragment { actionBarHandler.playVideo(); } }); + + Button similarVideosButton = (Button) activity.findViewById(R.id.detailShowSimilarButton); + similarVideosButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(activity, VideoItemListActivity.class); + intent.putExtra(VideoItemListActivity.VIDEO_INFO_ITEMS, currentVideoInfo.relatedVideos); + activity.startActivity(intent); + } + }); } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index 4caeec171..43d35b790 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -3,8 +3,12 @@ package org.schabi.newpipe; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v4.app.NavUtils; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -12,6 +16,8 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.ImageView; +import java.util.Arrays; + /** * Copyright (C) Christian Schabesberger 2015 * VideoItemListActivity.java is part of NewPipe. @@ -34,9 +40,19 @@ public class VideoItemListActivity extends AppCompatActivity implements VideoItemListFragment.Callbacks { private static final String TAG = VideoItemListFragment.class.toString(); + + // arguments to give to this activity + public static final String VIDEO_INFO_ITEMS = "video_info_items"; + + // savedInstanceBundle arguments private static final String QUERY = "query"; private static final String STREAMING_SERVICE = "streaming_service"; + // activity modes + private static final int SEARCH_MODE = 0; + private static final int PRESENT_VIDEOS_MODE = 1; + + private int mode = SEARCH_MODE; private int currentStreamingServiceId = -1; private String searchQuery = ""; @@ -87,17 +103,29 @@ public class VideoItemListActivity extends AppCompatActivity super.onCreate(savedInstanceState); setContentView(R.layout.activity_videoitem_list); - listFragment = (VideoItemListFragment) - getSupportFragmentManager().findFragmentById(R.id.videoitem_list); - //-------- remove this line when multiservice support is implemented ---------- currentStreamingServiceId = ServiceList.getIdOfService("Youtube"); //----------------------------------------------------------------------------- - VideoItemListFragment listFragment = (VideoItemListFragment) getSupportFragmentManager() + listFragment = (VideoItemListFragment) getSupportFragmentManager() .findFragmentById(R.id.videoitem_list); listFragment.setStreamingService(ServiceList.getService(currentStreamingServiceId)); - if(savedInstanceState != null) { + Bundle arguments = getIntent().getExtras(); + + if(arguments != null) { + Parcelable[] p = arguments.getParcelableArray(VIDEO_INFO_ITEMS); + if(p != null) { + mode = PRESENT_VIDEOS_MODE; + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + //todo: make this more efficient + listFragment.present(Arrays.copyOf(p, p.length, VideoInfoItem[].class)); + } + } + + + if(savedInstanceState != null + && mode != PRESENT_VIDEOS_MODE) { searchQuery = savedInstanceState.getString(QUERY); currentStreamingServiceId = savedInstanceState.getInt(STREAMING_SERVICE); if(!searchQuery.isEmpty()) { @@ -120,15 +148,18 @@ public class VideoItemListActivity extends AppCompatActivity .setActivateOnItemClick(true); SearchView searchView = (SearchView)findViewById(R.id.searchViewTablet); - // Somehow the seticonifiedbydefault property set by the layout xml is not working on - // the support version on SearchView, so it needs to be set programmatically. - searchView.setIconifiedByDefault(false); - searchView.setIconified(false); - searchView.setOnQueryTextListener(new SearchVideoQueryListener()); + if(mode != PRESENT_VIDEOS_MODE) { + // Somehow the seticonifiedbydefault property set by the layout xml is not working on + // the support version on SearchView, so it needs to be set programmatically. + searchView.setIconifiedByDefault(false); + searchView.setIconified(false); + searchView.setOnQueryTextListener(new SearchVideoQueryListener()); + } else { + searchView.setVisibility(View.GONE); + } } SettingsActivity.initSettings(this); - } /** @@ -178,7 +209,8 @@ public class VideoItemListActivity extends AppCompatActivity super.onCreateOptionsMenu(menu); this.menu = menu; MenuInflater inflater = getMenuInflater(); - if(findViewById(R.id.videoitem_detail_container) == null) { + if(mode != PRESENT_VIDEOS_MODE && + findViewById(R.id.videoitem_detail_container) == null) { inflater.inflate(R.menu.videoitem_list, menu); MenuItem searchItem = menu.findItem(R.id.action_search); SearchView searchView = (SearchView) searchItem.getActionView(); @@ -198,14 +230,23 @@ public class VideoItemListActivity extends AppCompatActivity @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); - if(id == R.id.action_settings) { - Intent intent = new Intent(this, SettingsActivity.class); - startActivity(intent); - } else { - return videoFragment.onOptionsItemSelected(item) || + + switch(id) { + case android.R.id.home: { + Intent intent = new Intent(this, VideoItemListActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + NavUtils.navigateUpTo(this, intent); + return true; + } + case R.id.action_settings: { + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + return true; + } + default: + return videoFragment.onOptionsItemSelected(item) || super.onOptionsItemSelected(item); } - return true; } @Override diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index dd7ae61dc..16b77f6c3 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -13,6 +13,7 @@ import android.widget.ListView; import android.widget.Toast; import java.net.URL; +import java.util.Arrays; import java.util.Vector; @@ -41,6 +42,11 @@ public class VideoItemListFragment extends ListFragment { private StreamingService streamingService = null; private VideoListAdapter videoListAdapter; + // activity modes + private static final int SEARCH_MODE = 0; + private static final int PRESENT_VIDEOS_MODE = 1; + + private int mode = SEARCH_MODE; private String query = ""; private int lastPage = 0; @@ -50,6 +56,7 @@ public class VideoItemListFragment extends ListFragment { private LoadThumbsRunnable loadThumbsRunnable = null; // used to track down if results posted by threads ar still valid private int currentRequestId = -1; + private ListView list; private class ResultRunnable implements Runnable { private SearchEngine.Result result; @@ -161,7 +168,18 @@ public class VideoItemListFragment extends ListFragment { } } + public void present(VideoInfoItem[] videoList) { + mode = PRESENT_VIDEOS_MODE; + setListShown(true); + getListView().smoothScrollToPosition(0); + + // inefficient like hell i know (welcome to the world of java) + //todo: make this more efficient + updateList(new Vector<>(Arrays.asList(videoList))); + } + public void search(String query) { + mode = SEARCH_MODE; this.query = query; this.lastPage = 1; videoListAdapter.clearVideoList(); @@ -271,6 +289,7 @@ public class VideoItemListFragment extends ListFragment { @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + list = getListView(); videoListAdapter = new VideoListAdapter(getActivity(), this); setListAdapter(videoListAdapter); @@ -282,8 +301,6 @@ public class VideoItemListFragment extends ListFragment { } getListView().setOnScrollListener(new AbsListView.OnScrollListener() { - private static final float OVERSCROLL_THRESHOLD_IN_PIXELS = 100; - private float downY; long lastScrollDate = 0; @Override @@ -292,8 +309,8 @@ public class VideoItemListFragment extends ListFragment { @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - ListView list = getListView(); - if (list.getChildAt(0) != null + if (mode != PRESENT_VIDEOS_MODE + && list.getChildAt(0) != null && list.getLastVisiblePosition() == list.getAdapter().getCount() - 1 && list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) { long time = System.currentTimeMillis(); diff --git a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java index 92a161c5b..a7bb13826 100644 --- a/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/youtube/YoutubeExtractor.java @@ -233,10 +233,8 @@ public class YoutubeExtractor implements Extractor { resolveResolutionString(itag))); } } - videoInfo.videoStreams = new VideoInfo.VideoStream[videoStreams.size()]; - for(int i = 0; i < videoStreams.size(); i++) { - videoInfo.videoStreams[i] = videoStreams.get(i); - } + videoInfo.videoStreams = + videoStreams.toArray(new VideoInfo.VideoStream[videoStreams.size()]); } catch (Exception e) { e.printStackTrace(); @@ -310,15 +308,15 @@ public class YoutubeExtractor implements Extractor { int i = 0; // related videos - videoInfo.relatedVideos = new Vector<>(); + Vector relatedVideos = new Vector<>(); for(Element li : doc.select("ul[id=\"watch-related\"]").first().children()) { // first check if we have a playlist. If so leave them out if(li.select("a[class*=\"content-link\"]").first() != null) { - videoInfo.relatedVideos.add(extractVideoInfoItem(li)); + relatedVideos.add(extractVideoInfoItem(li)); i++; } } - + videoInfo.relatedVideos = relatedVideos.toArray(new VideoInfoItem[relatedVideos.size()]); return videoInfo; } @@ -390,11 +388,7 @@ public class YoutubeExtractor implements Extractor { } catch(Exception e) { e.printStackTrace(); } - VideoInfo.AudioStream[] output = new VideoInfo.AudioStream[audioStreams.size()]; - for(int i = 0; i < output.length; i++) { - output[i] = audioStreams.get(i); - } - return output; + return audioStreams.toArray(new VideoInfo.AudioStream[audioStreams.size()]); } private VideoInfoItem extractVideoInfoItem(Element li) { diff --git a/app/src/main/res/layout-land/fragment_videoitem_detail.xml b/app/src/main/res/layout-land/fragment_videoitem_detail.xml index 3b4206b06..9e1d2885d 100644 --- a/app/src/main/res/layout-land/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-land/fragment_videoitem_detail.xml @@ -188,10 +188,18 @@ android:layout_alignParentLeft="true" /> +