1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 16:40:32 +00:00

add recycler view adapter

This commit is contained in:
Christian Schabesberger 2016-08-02 00:58:52 +02:00
parent 4164195fae
commit f34cacbc5c
9 changed files with 214 additions and 73 deletions

View File

@ -45,5 +45,4 @@ dependencies {
compile 'com.google.code.gson:gson:2.4' compile 'com.google.code.gson:gson:2.4'
compile 'com.nononsenseapps:filepicker:2.0.5' compile 'com.nononsenseapps:filepicker:2.0.5'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
//compile 'net.sourceforge.cssparser:cssparser:0.9.20'
} }

View File

@ -1,7 +1,6 @@
package org.schabi.newpipe; package org.schabi.newpipe;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@ -18,8 +17,6 @@ import android.widget.ProgressBar;
import android.widget.Toast; import android.widget.Toast;
import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.schabi.newpipe.extractor.ChannelExtractor; import org.schabi.newpipe.extractor.ChannelExtractor;
import org.schabi.newpipe.extractor.ChannelInfo; import org.schabi.newpipe.extractor.ChannelInfo;
@ -34,40 +31,10 @@ import java.util.ArrayList;
public class ChannelActivity extends AppCompatActivity { public class ChannelActivity extends AppCompatActivity {
private static final String TAG = ChannelActivity.class.toString(); private static final String TAG = ChannelActivity.class.toString();
private View rootView = null; private View rootView = null;
class FailedThumbnailListener implements ImageLoadingListener {
int serviceId = -1;
public FailedThumbnailListener(int serviceId) {
this.serviceId= serviceId;
}
@Override
public void onLoadingStarted(String imageUri, View view) {
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
ErrorActivity.reportError(ChannelActivity.this,
failReason.getCause(), null, rootView,
ErrorActivity.ErrorInfo.make(ErrorActivity.LOAD_IMAGE,
ServiceList.getNameOfService(serviceId), imageUri,
R.string.could_not_load_image));
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
}
}
// intent const // intent const
public static final String CHANNEL_URL = "channel_url"; public static final String CHANNEL_URL = "channel_url";
public static final String SERVICE_ID = "service_id"; public static final String SERVICE_ID = "service_id";
@ -137,8 +104,8 @@ public class ChannelActivity extends AppCompatActivity {
private void updateUi(final ChannelInfo info) { private void updateUi(final ChannelInfo info) {
VideoInfoItemViewCreator viCreator = StreamInfoItemViewCreator viCreator =
new VideoInfoItemViewCreator(LayoutInflater.from(this), this, rootView); new StreamInfoItemViewCreator(LayoutInflater.from(this), this, rootView);
CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) findViewById(R.id.channel_toolbar_layout); CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) findViewById(R.id.channel_toolbar_layout);
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar); ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
ImageView channelBanner = (ImageView) findViewById(R.id.channel_banner_image); ImageView channelBanner = (ImageView) findViewById(R.id.channel_banner_image);
@ -156,14 +123,14 @@ public class ChannelActivity extends AppCompatActivity {
if(info.banner_url != null && !info.banner_url.isEmpty()) { if(info.banner_url != null && !info.banner_url.isEmpty()) {
imageLoader.displayImage(info.banner_url, channelBanner, imageLoader.displayImage(info.banner_url, channelBanner,
new FailedThumbnailListener(info.service_id)); new ImageErrorLoadingListener(this, rootView ,info.service_id));
} }
if(info.avatar_url != null && !info.avatar_url.isEmpty()) { if(info.avatar_url != null && !info.avatar_url.isEmpty()) {
avatarView.setVisibility(View.VISIBLE); avatarView.setVisibility(View.VISIBLE);
haloView.setVisibility(View.VISIBLE); haloView.setVisibility(View.VISIBLE);
imageLoader.displayImage(info.avatar_url, avatarView, imageLoader.displayImage(info.avatar_url, avatarView,
new FailedThumbnailListener(info.service_id)); new ImageErrorLoadingListener(this, rootView ,info.service_id));
} }
if(info.feed_url != null && !info.feed_url.isEmpty()) { if(info.feed_url != null && !info.feed_url.isEmpty()) {
@ -182,7 +149,7 @@ public class ChannelActivity extends AppCompatActivity {
initVideos(info, viCreator); initVideos(info, viCreator);
} }
private void initVideos(final ChannelInfo info, VideoInfoItemViewCreator viCreator) { private void initVideos(final ChannelInfo info, StreamInfoItemViewCreator viCreator) {
LinearLayout streamLayout = (LinearLayout) findViewById(R.id.channel_streams_view); LinearLayout streamLayout = (LinearLayout) findViewById(R.id.channel_streams_view);
ArrayList<StreamPreviewInfo> streamsList = new ArrayList<>(info.related_streams); ArrayList<StreamPreviewInfo> streamsList = new ArrayList<>(info.related_streams);

View File

@ -15,7 +15,7 @@ import org.schabi.newpipe.extractor.ServiceList;
* Created by Christian Schabesberger on 01.08.16. * Created by Christian Schabesberger on 01.08.16.
* *
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org> * Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoInfoItemViewCreator.java is part of NewPipe. * StreamInfoItemViewCreator.java is part of NewPipe.
* *
* NewPipe is free software: you can redistribute it and/or modify * NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by

View File

@ -0,0 +1,29 @@
package org.schabi.newpipe;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Created by the-scrabi on 01.08.16.
*/
public class StreamInfoItemHolder extends RecyclerView.ViewHolder {
public ImageView itemThumbnailView;
public TextView itemVideoTitleView,
itemUploaderView,
itemDurationView,
itemUploadDateView,
itemViewCountView;
public StreamInfoItemHolder(View v) {
super(v);
itemThumbnailView = (ImageView) v.findViewById(R.id.itemThumbnailView);
itemVideoTitleView = (TextView) v.findViewById(R.id.itemVideoTitleView);
itemUploaderView = (TextView) v.findViewById(R.id.itemUploaderView);
itemDurationView = (TextView) v.findViewById(R.id.itemDurationView);
itemUploadDateView = (TextView) v.findViewById(R.id.itemUploadDateView);
itemViewCountView = (TextView) v.findViewById(R.id.itemViewCountView);
}
}

View File

@ -20,7 +20,7 @@ import org.schabi.newpipe.extractor.StreamPreviewInfo;
* Created by Christian Schabesberger on 24.10.15. * Created by Christian Schabesberger on 24.10.15.
* *
* Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org> * Copyright (C) Christian Schabesberger 2015 <chris.schabesberger@mailbox.org>
* VideoInfoItemViewCreator.java is part of NewPipe. * StreamInfoItemViewCreator.java is part of NewPipe.
* *
* NewPipe is free software: you can redistribute it and/or modify * NewPipe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -36,7 +36,16 @@ import org.schabi.newpipe.extractor.StreamPreviewInfo;
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>. * along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
*/ */
public class VideoInfoItemViewCreator { public class StreamInfoItemViewCreator {
private class ViewHolder {
public ImageView itemThumbnailView;
public TextView itemVideoTitleView,
itemUploaderView,
itemDurationView,
itemUploadDateView,
itemViewCountView;
}
private View rootView = null; //root view of the activty private View rootView = null; //root view of the activty
private Activity activity = null; private Activity activity = null;
@ -44,7 +53,7 @@ public class VideoInfoItemViewCreator {
private ImageLoader imageLoader = ImageLoader.getInstance(); private ImageLoader imageLoader = ImageLoader.getInstance();
private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build(); private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build();
public VideoInfoItemViewCreator(LayoutInflater inflater, Activity a, View rootView) { public StreamInfoItemViewCreator(LayoutInflater inflater, Activity a, View rootView) {
this.inflater = inflater; this.inflater = inflater;
activity = a; activity = a;
this.rootView = rootView; this.rootView = rootView;
@ -95,12 +104,16 @@ public class VideoInfoItemViewCreator {
holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail); holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail);
if(info.thumbnail_url != null && !info.thumbnail_url.isEmpty()) { if(info.thumbnail_url != null && !info.thumbnail_url.isEmpty()) {
imageLoader.displayImage(info.thumbnail_url, holder.itemThumbnailView, displayImageOptions); imageLoader.displayImage(info.thumbnail_url,
holder.itemThumbnailView,
displayImageOptions,
new ImageErrorLoadingListener(activity, rootView, info.service_id));
} }
return convertView; return convertView;
} }
public View setupView(View convertView, final StreamPreviewInfo info) { public View setupView(View convertView, final StreamPreviewInfo info) {
convertView.setClickable(true); convertView.setClickable(true);
convertView.setFocusable(true); convertView.setFocusable(true);
@ -134,12 +147,7 @@ public class VideoInfoItemViewCreator {
return convertView; return convertView;
} }
private class ViewHolder { public static String shortViewCount(Long viewCount){
public ImageView itemThumbnailView;
public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView, itemViewCountView;
}
private String shortViewCount(Long viewCount){
if(viewCount >= 1000000000){ if(viewCount >= 1000000000){
return Long.toString(viewCount/1000000000)+"B views"; return Long.toString(viewCount/1000000000)+"B views";
}else if(viewCount>=1000000){ }else if(viewCount>=1000000){

View File

@ -0,0 +1,153 @@
package org.schabi.newpipe;
import android.app.Activity;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
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.extractor.AbstractVideoInfo;
import org.schabi.newpipe.extractor.StreamPreviewInfo;
import java.util.List;
import java.util.Vector;
/**
* Created by the-scrabi on 01.08.16.
*/
public class StreamInfoListAdapter extends RecyclerView.Adapter<StreamInfoItemHolder> {
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();
StreamInfoListAdapter(Activity a, View rootView) {
activity = a;
this.rootView = rootView;
}
@Override
public int getItemCount() {
return streamList.size();
}
@Override
public StreamInfoItemHolder onCreateViewHolder(ViewGroup parent, int i) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_item, parent, false);
return new StreamInfoItemHolder(itemView);
}
@Override
public void onBindViewHolder(StreamInfoItemHolder holder, int i) {
StreamPreviewInfo info = 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(StreamInfoItemViewCreator.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));
}
}
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

@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory; import android.graphics.BitmapFactory;
import android.graphics.Point; import android.graphics.Point;
@ -50,7 +49,6 @@ import java.util.Vector;
import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.AudioStream; import org.schabi.newpipe.extractor.AudioStream;
import org.schabi.newpipe.extractor.ChannelExtractor;
import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.MediaFormat;
import org.schabi.newpipe.extractor.ParsingException; import org.schabi.newpipe.extractor.ParsingException;
import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.ServiceList;
@ -266,8 +264,8 @@ public class VideoItemDetailFragment extends Fragment {
private void updateInfo(final StreamInfo info) { private void updateInfo(final StreamInfo info) {
try { try {
Context c = getContext(); Context c = getContext();
VideoInfoItemViewCreator videoItemViewCreator = StreamInfoItemViewCreator videoItemViewCreator =
new VideoInfoItemViewCreator(LayoutInflater.from(getActivity()), new StreamInfoItemViewCreator(LayoutInflater.from(getActivity()),
getActivity(), rootView); getActivity(), rootView);
RelativeLayout textContentLayout = RelativeLayout textContentLayout =
@ -688,7 +686,7 @@ public class VideoItemDetailFragment extends Fragment {
return 0; return 0;
} }
private void initSimilarVideos(final StreamInfo info, VideoInfoItemViewCreator videoItemViewCreator) { private void initSimilarVideos(final StreamInfo info, StreamInfoItemViewCreator videoItemViewCreator) {
LinearLayout similarLayout = (LinearLayout) activity.findViewById(R.id.similarVideosView); LinearLayout similarLayout = (LinearLayout) activity.findViewById(R.id.similarVideosView);
ArrayList<StreamPreviewInfo> similarStreamsList = new ArrayList<>(info.related_streams); ArrayList<StreamPreviewInfo> similarStreamsList = new ArrayList<>(info.related_streams);

View File

@ -36,12 +36,12 @@ import java.util.Vector;
class VideoListAdapter extends BaseAdapter { class VideoListAdapter extends BaseAdapter {
private final Context context; private final Context context;
private final VideoInfoItemViewCreator viewCreator; private final StreamInfoItemViewCreator viewCreator;
private Vector<StreamPreviewInfo> videoList = new Vector<>(); private Vector<StreamPreviewInfo> videoList = new Vector<>();
private final ListView listView; private final ListView listView;
public VideoListAdapter(Activity activity, VideoItemListFragment videoListFragment) { public VideoListAdapter(Activity activity, VideoItemListFragment videoListFragment) {
viewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(activity), activity, null); viewCreator = new StreamInfoItemViewCreator(LayoutInflater.from(activity), activity, null);
this.listView = videoListFragment.getListView(); this.listView = videoListFragment.getListView();
this.listView.setDivider(null); this.listView.setDivider(null);
this.listView.setDividerHeight(0); this.listView.setDividerHeight(0);

View File

@ -101,29 +101,16 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
@Override @Override
public String getBannerUrl() throws ParsingException { public String getBannerUrl() throws ParsingException {
String cssContent = "";
try { try {
Element el = doc.select("div[id=\"gh-banner\"]").first().select("style").first(); Element el = doc.select("div[id=\"gh-banner\"]").first().select("style").first();
cssContent = el.html(); String cssContent = el.html();
// todo: parse this using a css parser
/*
CSSStyleSheet sheet = cssParser.parseStyleSheet(
new org.w3c.css.sac.InputSource(
new StringReader(cssContent)), null, null);
CSSRuleList rules = sheet.getCssRules();
for (int i = 0; i < rules.getLength(); i++) {
final CSSRule rule = rules.item(i);
System.out.println(rule.getCssText());
}
*/
String url = "https:" + Parser.matchGroup1("url\\((.*)\\)", cssContent); String url = "https:" + Parser.matchGroup1("url\\((.*)\\)", cssContent);
if(url.contains("s.ytimg.com")) { if(url.contains("s.ytimg.com")) {
return null; return null;
} else { } else {
return url; return url;
} }
/* } catch(CSSParseException csse) {
throw new ParsingException("Could not parse css: " + cssContent); */
} catch(Exception e) { } catch(Exception e) {
throw new ParsingException("Could not get Banner", e); throw new ParsingException("Could not get Banner", e);
} }