1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 08:30:44 +00:00

similar videos scroll bug workaround

This commit is contained in:
Christian Schabesberger 2016-09-26 17:02:55 +02:00
parent 85e2b124ab
commit 60e18aa045
7 changed files with 351 additions and 304 deletions

View File

@ -26,6 +26,7 @@ import org.schabi.newpipe.extractor.ExtractionException;
import org.schabi.newpipe.extractor.ParsingException; import org.schabi.newpipe.extractor.ParsingException;
import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoListAdapter; import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
@ -84,7 +85,7 @@ public class ChannelActivity extends AppCompatActivity {
final LinearLayoutManager layoutManager = new LinearLayoutManager(this); final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(infoListAdapter); recyclerView.setAdapter(infoListAdapter);
infoListAdapter.setOnItemSelectedListener(new InfoListAdapter.OnItemSelectedListener() { infoListAdapter.setOnItemSelectedListener(new InfoItemBuilder.OnItemSelectedListener() {
@Override @Override
public void selected(String url) { public void selected(String url) {
Intent detailIntent = new Intent(ChannelActivity.this, VideoItemDetailActivity.class); Intent detailIntent = new Intent(ChannelActivity.this, VideoItemDetailActivity.class);

View File

@ -14,7 +14,6 @@ import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.Html; import android.text.Html;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
@ -27,6 +26,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@ -43,6 +43,8 @@ import java.util.Vector;
import org.schabi.newpipe.ActivityCommunicator; import org.schabi.newpipe.ActivityCommunicator;
import org.schabi.newpipe.ChannelActivity; import org.schabi.newpipe.ChannelActivity;
import org.schabi.newpipe.extractor.StreamPreviewInfo;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.ImageErrorLoadingListener; import org.schabi.newpipe.ImageErrorLoadingListener;
import org.schabi.newpipe.Localization; import org.schabi.newpipe.Localization;
@ -53,7 +55,6 @@ import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.ServiceList;
import org.schabi.newpipe.extractor.StreamInfo; import org.schabi.newpipe.extractor.StreamInfo;
import org.schabi.newpipe.extractor.VideoStream; import org.schabi.newpipe.extractor.VideoStream;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.player.BackgroundPlayer; import org.schabi.newpipe.player.BackgroundPlayer;
import org.schabi.newpipe.player.PlayVideoActivity; import org.schabi.newpipe.player.PlayVideoActivity;
import org.schabi.newpipe.player.ExoPlayerActivity; import org.schabi.newpipe.player.ExoPlayerActivity;
@ -110,7 +111,7 @@ public class VideoItemDetailFragment extends Fragment {
private DisplayImageOptions displayImageOptions = private DisplayImageOptions displayImageOptions =
new DisplayImageOptions.Builder().cacheInMemory(true).build(); new DisplayImageOptions.Builder().cacheInMemory(true).build();
private InfoListAdapter similarStreamsAdapter = null; private InfoItemBuilder infoItemBuilder = null;
public interface OnInvokeCreateOptionsMenuListener { public interface OnInvokeCreateOptionsMenuListener {
void createOptionsMenu(); void createOptionsMenu();
@ -119,7 +120,6 @@ public class VideoItemDetailFragment extends Fragment {
private OnInvokeCreateOptionsMenuListener onInvokeCreateOptionsMenuListener; private OnInvokeCreateOptionsMenuListener onInvokeCreateOptionsMenuListener;
private void updateInfo(final StreamInfo info) { private void updateInfo(final StreamInfo info) {
try {
Activity a = getActivity(); Activity a = getActivity();
RelativeLayout textContentLayout = RelativeLayout textContentLayout =
@ -145,10 +145,7 @@ public class VideoItemDetailFragment extends Fragment {
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
if(info.next_video != null) { if(info.next_video != null) {
InfoListAdapter adapter = new InfoListAdapter(a, rootView); infoItemBuilder.setOnItemSelectedListener(new InfoItemBuilder.OnItemSelectedListener() {
nextStreamView.setAdapter(adapter);
nextStreamView.setLayoutManager(new LinearLayoutManager(a));
adapter.setOnItemSelectedListener(new InfoListAdapter.OnItemSelectedListener() {
@Override @Override
public void selected(String url) { public void selected(String url) {
openStreamUrl(url); openStreamUrl(url);
@ -159,7 +156,6 @@ public class VideoItemDetailFragment extends Fragment {
activity.findViewById(R.id.detail_similar_title).setVisibility(View.GONE); activity.findViewById(R.id.detail_similar_title).setVisibility(View.GONE);
} }
textContentLayout.setVisibility(View.VISIBLE); textContentLayout.setVisibility(View.VISIBLE);
if (android.os.Build.VERSION.SDK_INT < 18) { if (android.os.Build.VERSION.SDK_INT < 18) {
playVideoButton.setVisibility(View.VISIBLE); playVideoButton.setVisibility(View.VISIBLE);
@ -291,11 +287,6 @@ public class VideoItemDetailFragment extends Fragment {
} }
initThumbnailViews(info); initThumbnailViews(info);
} catch (java.lang.NullPointerException e) {
Log.w(TAG, "updateInfo(): Fragment closed before thread ended work... or else");
e.printStackTrace();
}
} }
private void initThumbnailViews(final StreamInfo info) { private void initThumbnailViews(final StreamInfo info) {
@ -527,7 +518,10 @@ public class VideoItemDetailFragment extends Fragment {
} }
private void initSimilarVideos(final StreamInfo info) { private void initSimilarVideos(final StreamInfo info) {
similarStreamsAdapter.addStreamItemList(info.related_streams); LinearLayout similarLayout = (LinearLayout) activity.findViewById(R.id.similar_streams_view);
for (final StreamPreviewInfo item : info.related_streams) {
similarLayout.addView(infoItemBuilder.buildView(similarLayout, item));
}
} }
private void onErrorBlockedByGema() { private void onErrorBlockedByGema() {
@ -640,6 +634,9 @@ public class VideoItemDetailFragment extends Fragment {
public void onActivityCreated(Bundle savedInstanceBundle) { public void onActivityCreated(Bundle savedInstanceBundle) {
super.onActivityCreated(savedInstanceBundle); super.onActivityCreated(savedInstanceBundle);
Activity a = getActivity(); Activity a = getActivity();
infoItemBuilder = new InfoItemBuilder(a, a.findViewById(android.R.id.content));
if (android.os.Build.VERSION.SDK_INT < 18) { if (android.os.Build.VERSION.SDK_INT < 18) {
playVideoButton = (FloatingActionButton) a.findViewById(R.id.play_video_button); playVideoButton = (FloatingActionButton) a.findViewById(R.id.play_video_button);
} }
@ -681,17 +678,6 @@ public class VideoItemDetailFragment extends Fragment {
} }
}); });
} }
similarStreamsAdapter = new InfoListAdapter(getActivity(), rootView);
RecyclerView rv = (RecyclerView) getActivity().findViewById(R.id.similar_streams_view);
rv.setLayoutManager(new LinearLayoutManager(getActivity()));
rv.setAdapter(similarStreamsAdapter);
similarStreamsAdapter.setOnItemSelectedListener(new InfoListAdapter.OnItemSelectedListener() {
@Override
public void selected(String url) {
openStreamUrl(url);
}
});
} }
} }

View File

@ -0,0 +1,174 @@
package org.schabi.newpipe.info_list;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.ImageErrorLoadingListener;
import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.AbstractVideoInfo;
import org.schabi.newpipe.extractor.StreamPreviewInfo;
/**
* Created by Christian Schabesberger on 26.09.16.
*
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
* InfoItemBuilder.java is part of NewPipe.
*
* NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* NewPipe is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/
public class InfoItemBuilder {
public interface OnItemSelectedListener {
void selected(String url);
}
private Activity activity = null;
private View rootView = null;
private ImageLoader imageLoader = ImageLoader.getInstance();
private DisplayImageOptions displayImageOptions =
new DisplayImageOptions.Builder().cacheInMemory(true).build();
private OnItemSelectedListener onItemSelectedListener;
public InfoItemBuilder(Activity a, View rootView) {
activity = a;
this.rootView = rootView;
}
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
this.onItemSelectedListener = onItemSelectedListener;
}
public void buildByHolder(InfoItemHolder holder, final StreamPreviewInfo info) {
// fill holder with information
holder.itemVideoTitleView.setText(info.title);
if(info.uploader != null && !info.uploader.isEmpty()) {
holder.itemUploaderView.setText(info.uploader);
} else {
holder.itemUploaderView.setVisibility(View.INVISIBLE);
}
if(info.duration > 0) {
holder.itemDurationView.setText(getDurationString(info.duration));
} else {
if(info.stream_type == AbstractVideoInfo.StreamType.LIVE_STREAM) {
holder.itemDurationView.setText(R.string.duration_live);
} else {
holder.itemDurationView.setVisibility(View.GONE);
}
}
if(info.view_count >= 0) {
holder.itemViewCountView.setText(shortViewCount(info.view_count));
} else {
holder.itemViewCountView.setVisibility(View.GONE);
}
if(info.upload_date != null && !info.upload_date.isEmpty()) {
holder.itemUploadDateView.setText(info.upload_date + "");
}
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
if(info.thumbnail_url != null && !info.thumbnail_url.isEmpty()) {
imageLoader.displayImage(info.thumbnail_url,
holder.itemThumbnailView,
displayImageOptions,
new ImageErrorLoadingListener(activity, rootView, info.service_id));
}
holder.itemButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemSelectedListener.selected(info.webpage_url);
}
});
}
public View buildView(ViewGroup parent, final StreamPreviewInfo info) {
View streamPreviewView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_item, parent, false);
InfoItemHolder holder = new InfoItemHolder(streamPreviewView);
buildByHolder(holder, info);
return streamPreviewView;
}
public static String shortViewCount(Long viewCount){
if(viewCount >= 1000000000){
return Long.toString(viewCount/1000000000)+"B views";
}else if(viewCount>=1000000){
return Long.toString(viewCount/1000000)+"M views";
}else if(viewCount>=1000){
return Long.toString(viewCount/1000)+"K views";
}else {
return Long.toString(viewCount)+" views";
}
}
public static String getDurationString(int duration) {
String output = "";
int days = duration / (24 * 60 * 60); /* greater than a day */
duration %= (24 * 60 * 60);
int hours = duration / (60 * 60); /* greater than an hour */
duration %= (60 * 60);
int minutes = duration / 60;
int seconds = duration % 60;
//handle days
if(days > 0) {
output = Integer.toString(days) + ":";
}
// handle hours
if(hours > 0 || !output.isEmpty()) {
if(hours > 0) {
if(hours >= 10 || output.isEmpty()) {
output += Integer.toString(hours);
} else {
output += "0" + Integer.toString(hours);
}
} else {
output += "00";
}
output += ":";
}
//handle minutes
if(minutes > 0 || !output.isEmpty()) {
if(minutes > 0) {
if(minutes >= 10 || output.isEmpty()) {
output += Integer.toString(minutes);
} else {
output += "0" + Integer.toString(minutes);
}
} else {
output += "00";
}
output += ":";
}
//handle seconds
if(output.isEmpty()) {
output += "0:";
}
if(seconds >= 10) {
output += Integer.toString(seconds);
} else {
output += "0" + Integer.toString(seconds);
}
return output;
}
}

View File

@ -39,27 +39,16 @@ import java.util.Vector;
public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> { public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
public interface OnItemSelectedListener { InfoItemBuilder infoItemBuilder = null;
void selected(String url); List<StreamPreviewInfo> streamList = new Vector<>();
}
private Activity activity = null;
private View rootView = null;
private List<StreamPreviewInfo> streamList = new Vector<>();
private ImageLoader imageLoader = ImageLoader.getInstance();
private DisplayImageOptions displayImageOptions =
new DisplayImageOptions.Builder().cacheInMemory(true).build();
private OnItemSelectedListener onItemSelectedListener;
public InfoListAdapter(Activity a, View rootView) { public InfoListAdapter(Activity a, View rootView) {
activity = a; infoItemBuilder = new InfoItemBuilder(a, rootView);
this.rootView = rootView;
} }
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) { public void setOnItemSelectedListener
this.onItemSelectedListener = onItemSelectedListener; (InfoItemBuilder.OnItemSelectedListener onItemSelectedListener) {
infoItemBuilder.setOnItemSelectedListener(onItemSelectedListener);
} }
public void addStreamItemList(List<StreamPreviewInfo> videos) { public void addStreamItemList(List<StreamPreviewInfo> videos) {
@ -89,112 +78,6 @@ public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
@Override @Override
public void onBindViewHolder(InfoItemHolder holder, int i) { public void onBindViewHolder(InfoItemHolder holder, int i) {
final StreamPreviewInfo info = streamList.get(i); infoItemBuilder.buildByHolder(holder, streamList.get(i));
// fill holder with information
holder.itemVideoTitleView.setText(info.title);
if(info.uploader != null && !info.uploader.isEmpty()) {
holder.itemUploaderView.setText(info.uploader);
} else {
holder.itemUploaderView.setVisibility(View.INVISIBLE);
}
if(info.duration > 0) {
holder.itemDurationView.setText(getDurationString(info.duration));
} else {
if(info.stream_type == AbstractVideoInfo.StreamType.LIVE_STREAM) {
holder.itemDurationView.setText(R.string.duration_live);
} else {
holder.itemDurationView.setVisibility(View.GONE);
}
}
if(info.view_count >= 0) {
holder.itemViewCountView.setText(shortViewCount(info.view_count));
} else {
holder.itemViewCountView.setVisibility(View.GONE);
}
if(info.upload_date != null && !info.upload_date.isEmpty()) {
holder.itemUploadDateView.setText(info.upload_date + "");
}
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
if(info.thumbnail_url != null && !info.thumbnail_url.isEmpty()) {
imageLoader.displayImage(info.thumbnail_url,
holder.itemThumbnailView,
displayImageOptions,
new ImageErrorLoadingListener(activity, rootView, info.service_id));
}
holder.itemButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemSelectedListener.selected(info.webpage_url);
}
});
}
public static String shortViewCount(Long viewCount){
if(viewCount >= 1000000000){
return Long.toString(viewCount/1000000000)+"B views";
}else if(viewCount>=1000000){
return Long.toString(viewCount/1000000)+"M views";
}else if(viewCount>=1000){
return Long.toString(viewCount/1000)+"K views";
}else {
return Long.toString(viewCount)+" views";
}
}
public static String getDurationString(int duration) {
String output = "";
int days = duration / (24 * 60 * 60); /* greater than a day */
duration %= (24 * 60 * 60);
int hours = duration / (60 * 60); /* greater than an hour */
duration %= (60 * 60);
int minutes = duration / 60;
int seconds = duration % 60;
//handle days
if(days > 0) {
output = Integer.toString(days) + ":";
}
// handle hours
if(hours > 0 || !output.isEmpty()) {
if(hours > 0) {
if(hours >= 10 || output.isEmpty()) {
output += Integer.toString(hours);
} else {
output += "0" + Integer.toString(hours);
}
} else {
output += "00";
}
output += ":";
}
//handle minutes
if(minutes > 0 || !output.isEmpty()) {
if(minutes > 0) {
if(minutes >= 10 || output.isEmpty()) {
output += Integer.toString(minutes);
} else {
output += "0" + Integer.toString(minutes);
}
} else {
output += "00";
}
output += ":";
}
//handle seconds
if(output.isEmpty()) {
output += "0:";
}
if(seconds >= 10) {
output += Integer.toString(seconds);
} else {
output += "0" + Integer.toString(seconds);
}
return output;
} }
} }

View File

@ -18,6 +18,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.Toast; import android.widget.Toast;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.detail.VideoItemDetailActivity; import org.schabi.newpipe.detail.VideoItemDetailActivity;
@ -189,7 +190,7 @@ public class SearchInfoItemFragment extends Fragment {
infoListAdapter = new InfoListAdapter(getActivity(), infoListAdapter = new InfoListAdapter(getActivity(),
getActivity().findViewById(android.R.id.content)); getActivity().findViewById(android.R.id.content));
infoListAdapter.setOnItemSelectedListener(new InfoListAdapter.OnItemSelectedListener() { infoListAdapter.setOnItemSelectedListener(new InfoItemBuilder.OnItemSelectedListener() {
@Override @Override
public void selected(String url) { public void selected(String url) {
Intent i = new Intent(getActivity(), VideoItemDetailActivity.class); Intent i = new Intent(getActivity(), VideoItemDetailActivity.class);

View File

@ -265,12 +265,13 @@
android:text="@string/similar_videos_btn_text" android:text="@string/similar_videos_btn_text"
android:layout_below="@id/detail_next_stream_content" android:layout_below="@id/detail_next_stream_content"
android:textAllCaps="true" /> android:textAllCaps="true" />
<android.support.v7.widget.RecyclerView <LinearLayout
android:id="@+id/similar_streams_view" android:id="@+id/similar_streams_view"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@id/detail_similar_title"/> android:layout_below="@id/detail_similar_title">
</LinearLayout>
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -267,12 +267,13 @@
android:text="@string/similar_videos_btn_text" android:text="@string/similar_videos_btn_text"
android:layout_below="@id/detail_next_stream_content" android:layout_below="@id/detail_next_stream_content"
android:textAllCaps="true" /> android:textAllCaps="true" />
<android.support.v7.widget.RecyclerView <LinearLayout
android:id="@+id/similar_streams_view" android:id="@+id/similar_streams_view"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@id/detail_similar_title"/> android:layout_below="@id/detail_similar_title">
</LinearLayout>
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>