From f34cacbc5c4fe1251037d9f174279998f9e62fbf Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Tue, 2 Aug 2016 00:58:52 +0200 Subject: [PATCH] add recycler view adapter --- app/build.gradle | 1 - .../org/schabi/newpipe/ChannelActivity.java | 45 +----- .../newpipe/ImageErrorLoadingListener.java | 2 +- .../schabi/newpipe/StreamInfoItemHolder.java | 29 ++++ ...or.java => StreamInfoItemViewCreator.java} | 28 ++-- .../schabi/newpipe/StreamInfoListAdapter.java | 153 ++++++++++++++++++ .../newpipe/VideoItemDetailFragment.java | 8 +- .../org/schabi/newpipe/VideoListAdapter.java | 4 +- .../youtube/YoutubeChannelExtractor.java | 17 +- 9 files changed, 214 insertions(+), 73 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/StreamInfoItemHolder.java rename app/src/main/java/org/schabi/newpipe/{VideoInfoItemViewCreator.java => StreamInfoItemViewCreator.java} (91%) create mode 100644 app/src/main/java/org/schabi/newpipe/StreamInfoListAdapter.java diff --git a/app/build.gradle b/app/build.gradle index 39c38eb38..cf45527ff 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -45,5 +45,4 @@ dependencies { compile 'com.google.code.gson:gson:2.4' compile 'com.nononsenseapps:filepicker:2.0.5' testCompile 'junit:junit:4.12' - //compile 'net.sourceforge.cssparser:cssparser:0.9.20' } diff --git a/app/src/main/java/org/schabi/newpipe/ChannelActivity.java b/app/src/main/java/org/schabi/newpipe/ChannelActivity.java index d673536d6..33c7c8eb8 100644 --- a/app/src/main/java/org/schabi/newpipe/ChannelActivity.java +++ b/app/src/main/java/org/schabi/newpipe/ChannelActivity.java @@ -1,7 +1,6 @@ package org.schabi.newpipe; import android.content.Intent; -import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -18,8 +17,6 @@ import android.widget.ProgressBar; import android.widget.Toast; 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.ChannelInfo; @@ -34,40 +31,10 @@ import java.util.ArrayList; public class ChannelActivity extends AppCompatActivity { + private static final String TAG = ChannelActivity.class.toString(); 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 public static final String CHANNEL_URL = "channel_url"; public static final String SERVICE_ID = "service_id"; @@ -137,8 +104,8 @@ public class ChannelActivity extends AppCompatActivity { private void updateUi(final ChannelInfo info) { - VideoInfoItemViewCreator viCreator = - new VideoInfoItemViewCreator(LayoutInflater.from(this), this, rootView); + StreamInfoItemViewCreator viCreator = + new StreamInfoItemViewCreator(LayoutInflater.from(this), this, rootView); CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) findViewById(R.id.channel_toolbar_layout); ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar); 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()) { 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()) { avatarView.setVisibility(View.VISIBLE); haloView.setVisibility(View.VISIBLE); 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()) { @@ -182,7 +149,7 @@ public class ChannelActivity extends AppCompatActivity { 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); ArrayList streamsList = new ArrayList<>(info.related_streams); diff --git a/app/src/main/java/org/schabi/newpipe/ImageErrorLoadingListener.java b/app/src/main/java/org/schabi/newpipe/ImageErrorLoadingListener.java index b63a7cb98..0447ed647 100644 --- a/app/src/main/java/org/schabi/newpipe/ImageErrorLoadingListener.java +++ b/app/src/main/java/org/schabi/newpipe/ImageErrorLoadingListener.java @@ -15,7 +15,7 @@ import org.schabi.newpipe.extractor.ServiceList; * Created by Christian Schabesberger on 01.08.16. * * Copyright (C) Christian Schabesberger 2015 - * VideoInfoItemViewCreator.java is part of NewPipe. + * StreamInfoItemViewCreator.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 diff --git a/app/src/main/java/org/schabi/newpipe/StreamInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/StreamInfoItemHolder.java new file mode 100644 index 000000000..8d0df8f89 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/StreamInfoItemHolder.java @@ -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); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/StreamInfoItemViewCreator.java similarity index 91% rename from app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java rename to app/src/main/java/org/schabi/newpipe/StreamInfoItemViewCreator.java index ae7024be2..ec2463a99 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java +++ b/app/src/main/java/org/schabi/newpipe/StreamInfoItemViewCreator.java @@ -20,7 +20,7 @@ import org.schabi.newpipe.extractor.StreamPreviewInfo; * Created by Christian Schabesberger on 24.10.15. * * Copyright (C) Christian Schabesberger 2015 - * VideoInfoItemViewCreator.java is part of NewPipe. + * StreamInfoItemViewCreator.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 @@ -36,7 +36,16 @@ import org.schabi.newpipe.extractor.StreamPreviewInfo; * along with NewPipe. If not, see . */ -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 Activity activity = null; @@ -44,7 +53,7 @@ public class VideoInfoItemViewCreator { private ImageLoader imageLoader = ImageLoader.getInstance(); 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; activity = a; this.rootView = rootView; @@ -95,12 +104,16 @@ public class VideoInfoItemViewCreator { holder.itemThumbnailView.setImageResource(R.drawable.dummy_thumbnail); 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; } + public View setupView(View convertView, final StreamPreviewInfo info) { convertView.setClickable(true); convertView.setFocusable(true); @@ -134,12 +147,7 @@ public class VideoInfoItemViewCreator { return convertView; } - private class ViewHolder { - public ImageView itemThumbnailView; - public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView, itemViewCountView; - } - - private String shortViewCount(Long viewCount){ + public static String shortViewCount(Long viewCount){ if(viewCount >= 1000000000){ return Long.toString(viewCount/1000000000)+"B views"; }else if(viewCount>=1000000){ diff --git a/app/src/main/java/org/schabi/newpipe/StreamInfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/StreamInfoListAdapter.java new file mode 100644 index 000000000..a7a466636 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/StreamInfoListAdapter.java @@ -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 { + + private Activity activity = null; + private View rootView = null; + private List 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; + } +} diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index 1ecd841bf..f0a5ef144 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; @@ -50,7 +49,6 @@ import java.util.Vector; import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.extractor.AudioStream; -import org.schabi.newpipe.extractor.ChannelExtractor; import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.ParsingException; import org.schabi.newpipe.extractor.ServiceList; @@ -266,8 +264,8 @@ public class VideoItemDetailFragment extends Fragment { private void updateInfo(final StreamInfo info) { try { Context c = getContext(); - VideoInfoItemViewCreator videoItemViewCreator = - new VideoInfoItemViewCreator(LayoutInflater.from(getActivity()), + StreamInfoItemViewCreator videoItemViewCreator = + new StreamInfoItemViewCreator(LayoutInflater.from(getActivity()), getActivity(), rootView); RelativeLayout textContentLayout = @@ -688,7 +686,7 @@ public class VideoItemDetailFragment extends Fragment { 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); ArrayList similarStreamsList = new ArrayList<>(info.related_streams); diff --git a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java index 885d063ab..1464d86b9 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java @@ -36,12 +36,12 @@ import java.util.Vector; class VideoListAdapter extends BaseAdapter { private final Context context; - private final VideoInfoItemViewCreator viewCreator; + private final StreamInfoItemViewCreator viewCreator; private Vector videoList = new Vector<>(); private final ListView listView; 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.setDivider(null); this.listView.setDividerHeight(0); diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java index d3029e14c..e697f0d3b 100644 --- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java @@ -101,29 +101,16 @@ public class YoutubeChannelExtractor extends ChannelExtractor { @Override public String getBannerUrl() throws ParsingException { - String cssContent = ""; + try { Element el = doc.select("div[id=\"gh-banner\"]").first().select("style").first(); - 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 cssContent = el.html(); String url = "https:" + Parser.matchGroup1("url\\((.*)\\)", cssContent); if(url.contains("s.ytimg.com")) { return null; } else { return url; } - /* } catch(CSSParseException csse) { - throw new ParsingException("Could not parse css: " + cssContent); */ } catch(Exception e) { throw new ParsingException("Could not get Banner", e); }