From 7cc1c0fbdd6f4fe69c9e083311467503e28e76e1 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Fri, 5 Feb 2016 17:09:29 +0100 Subject: [PATCH] merge code, and adjust code --- README.md | 1 - app/build.gradle | 10 +- .../YoutubeVideoExtractorDefaultTest.java | 1 + app/src/main/AndroidManifest.xml | 7 +- .../org/schabi/newpipe/ActionBarHandler.java | 6 +- app/src/main/java/org/schabi/newpipe/App.java | 7 + .../org/schabi/newpipe/BackgroundPlayer.java | 15 +- .../newpipe/VideoInfoItemViewCreator.java | 26 +- .../newpipe/VideoItemDetailFragment.java | 241 ++++++++++------- .../schabi/newpipe/VideoItemListFragment.java | 20 +- .../org/schabi/newpipe/VideoListAdapter.java | 20 -- .../services/youtube/YoutubeSearchEngine.java | 9 + .../main/res/drawable-nodpi/arrow_down.png | Bin 0 -> 3297 bytes app/src/main/res/drawable-nodpi/arrow_up.png | Bin 0 -> 3271 bytes .../layout-v18/fragment_videoitem_detail.xml | 219 ---------------- .../layout-v21/fragment_videoitem_detail.xml | 221 ---------------- .../res/layout/fragment_videoitem_detail.xml | 248 +++++++++++------- app/src/main/res/layout/paginate_footer.xml | 9 +- .../main/res/layout/player_notification.xml | 2 +- .../layout/player_notification_expanded.xml | 21 +- app/src/main/res/layout/video_item.xml | 43 ++- app/src/main/res/values/dimens.xml | 11 +- app/src/main/res/values/strings.xml | 2 +- screenshots/screenshot_1.png | Bin 6913 -> 331377 bytes screenshots/screenshot_2.png | Bin 327569 -> 272526 bytes screenshots/screenshot_3.png | Bin 252677 -> 267233 bytes screenshots/screenshot_4.png | Bin 259879 -> 184261 bytes screenshots/screenshot_5.png | Bin 173334 -> 169167 bytes screenshots/screenshot_6.png | Bin 167250 -> 0 bytes 29 files changed, 412 insertions(+), 727 deletions(-) create mode 100644 app/src/main/res/drawable-nodpi/arrow_down.png create mode 100644 app/src/main/res/drawable-nodpi/arrow_up.png delete mode 100644 app/src/main/res/layout-v18/fragment_videoitem_detail.xml delete mode 100644 app/src/main/res/layout-v21/fragment_videoitem_detail.xml delete mode 100644 screenshots/screenshot_6.png diff --git a/README.md b/README.md index b24ed14af..a11084c4e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Project status: [](screenshots/screenshot_3.png) [](screenshots/screenshot_4.png) [](screenshots/screenshot_5.png) -[](screenshots/screenshot_6.png) ## Description diff --git a/app/build.gradle b/app/build.gradle index 67b7e5326..05cdbb2f6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 23 - buildToolsVersion "23.0.2" + buildToolsVersion '23.0.2' defaultConfig { applicationId "org.schabi.newpipe" @@ -24,6 +24,10 @@ android { // but continue the build even when errors are found: abortOnError false } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } } dependencies { @@ -31,9 +35,11 @@ dependencies { compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:support-v4:23.1.1' compile 'com.android.support:design:23.1.1' - compile 'com.android.support:cardview-v7:23.1.1' compile 'com.android.support:recyclerview-v7:23.1.1' compile 'org.jsoup:jsoup:1.8.3' compile 'org.mozilla:rhino:1.7.7' compile 'info.guardianproject.netcipher:netcipher:1.2' + compile 'de.hdodenhof:circleimageview:2.0.0' + compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' + compile 'com.github.nirhart:parallaxscroll:1.0' } diff --git a/app/src/androidTest/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractorDefaultTest.java b/app/src/androidTest/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractorDefaultTest.java index b63e390c2..19246b54c 100644 --- a/app/src/androidTest/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractorDefaultTest.java +++ b/app/src/androidTest/java/org/schabi/newpipe/services/youtube/YoutubeVideoExtractorDefaultTest.java @@ -1,6 +1,7 @@ package org.schabi.newpipe.services.youtube; import android.test.AndroidTestCase; +import android.util.Log; import org.schabi.newpipe.Downloader; import org.schabi.newpipe.crawler.CrawlingException; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2f2ec061b..e30920404 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,8 @@ tools:ignore="AllowBackup"> + android:label="@string/app_name" + android:configChanges="orientation|screenSize"> @@ -26,7 +27,9 @@ + android:theme="@style/AppTheme" + android:configChanges="orientation|screenSize" + android:screenOrientation="portrait"> diff --git a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java index a5e7c8cff..b3451cbaf 100644 --- a/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java +++ b/app/src/main/java/org/schabi/newpipe/ActionBarHandler.java @@ -15,6 +15,7 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.widget.ArrayAdapter; +import android.widget.Toast; import org.schabi.newpipe.crawler.MediaFormat; import org.schabi.newpipe.crawler.VideoInfo; @@ -24,7 +25,7 @@ import java.util.List; /** * Created by Christian Schabesberger on 18.08.15. * - * Copyright (C) Christian Schabesberger 2016 + * Copyright (C) Christian Schabesberger 2015 * DetailsMenuHandler.java is part of NewPipe. * * NewPipe is free software: you can redistribute it and/or modify @@ -86,7 +87,7 @@ class ActionBarHandler { serviceId = id; } - public void setSetVideoThumbnail(Bitmap bitmap) { + public void setVideoThumbnail(Bitmap bitmap) { videoThumbnail = bitmap; } @@ -327,7 +328,6 @@ class ActionBarHandler { } public void playAudio() { - boolean externalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity) .getBoolean(activity.getString(R.string.use_external_audio_player_key), false); Intent intent; diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index d842e3f0a..1e51b6a34 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -5,6 +5,9 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; + import info.guardianproject.netcipher.NetCipher; import info.guardianproject.netcipher.proxy.OrbotHelper; @@ -34,6 +37,10 @@ public class App extends Application { public void onCreate() { super.onCreate(); + // Initialize image loader + ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this).build(); + ImageLoader.getInstance().init(config); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); if(prefs.getBoolean(getString(R.string.use_tor_key), false)) { OrbotHelper.requestStartTor(this); diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index cf0f88d05..7223928fe 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -53,7 +53,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare public static final String TITLE = "title"; public static final String WEB_URL = "web_url"; public static final String SERVICE_ID = "service_id"; - public static final String CHANNEL_NAME="channel_name"; + public static final String CHANNEL_NAME = "channel_name"; private volatile String webUrl = ""; private volatile int serviceId = -1; @@ -117,6 +117,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare private WifiManager.WifiLock wifiLock; private Bitmap videoThumbnail = null; private NotificationCompat.Builder noteBuilder; + private Notification note; public PlayerThread(String src, String title, BackgroundPlayer owner) { this.source = src; @@ -174,7 +175,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare filter.addAction(ACTION_STOP); registerReceiver(broadcastReceiver, filter); - Notification note = buildNotification(); + note = buildNotification(); startForeground(noteID, note); @@ -204,11 +205,21 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare if(action.equals(ACTION_PLAYPAUSE)) { if(mediaPlayer.isPlaying()) { mediaPlayer.pause(); + note.contentView.setImageViewResource(R.id.backgroundPlayPause, R.drawable.ic_play_circle_filled_white_24dp); + if(android.os.Build.VERSION.SDK_INT >=16){ + note.bigContentView.setImageViewResource(R.id.backgroundPlayPause, R.drawable.ic_play_circle_filled_white_24dp); + } + noteMgr.notify(noteID, note); } else { //reacquire CPU lock after auto-releasing it on pause mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); mediaPlayer.start(); + note.contentView.setImageViewResource(R.id.backgroundPlayPause, R.drawable.ic_pause_white_24dp); + if(android.os.Build.VERSION.SDK_INT >=16){ + note.bigContentView.setImageViewResource(R.id.backgroundPlayPause, R.drawable.ic_pause_white_24dp); + } + noteMgr.notify(noteID, note); } } else if(action.equals(ACTION_STOP)) { diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java index e254af02d..07f631146 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java @@ -8,6 +8,8 @@ import android.widget.ImageView; import android.widget.TextView; import org.schabi.newpipe.crawler.VideoPreviewInfo; +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; /** * Created by Christian Schabesberger on 24.10.15. @@ -31,6 +33,8 @@ import org.schabi.newpipe.crawler.VideoPreviewInfo; class VideoInfoItemViewCreator { private final LayoutInflater inflater; + private ImageLoader imageLoader = ImageLoader.getInstance(); + private DisplayImageOptions displayImageOptions = new DisplayImageOptions.Builder().cacheInMemory(true).build(); public VideoInfoItemViewCreator(LayoutInflater inflater) { this.inflater = inflater; @@ -46,6 +50,7 @@ class VideoInfoItemViewCreator { holder.itemUploaderView = (TextView) convertView.findViewById(R.id.itemUploaderView); holder.itemDurationView = (TextView) convertView.findViewById(R.id.itemDurationView); holder.itemUploadDateView = (TextView) convertView.findViewById(R.id.itemUploadDateView); + holder.itemViewCountView = (TextView) convertView.findViewById(R.id.itemViewCountView); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); @@ -59,18 +64,31 @@ class VideoInfoItemViewCreator { holder.itemVideoTitleView.setText(info.title); holder.itemUploaderView.setText(info.uploader); holder.itemDurationView.setText(info.duration); + holder.itemViewCountView.setText(shortViewCount(info.view_count)); if(!info.upload_date.isEmpty()) { - holder.itemUploadDateView.setText(info.upload_date); - } else { - holder.itemUploadDateView.setText(Localization.localizeViewCount(info.view_count, context)); + holder.itemUploadDateView.setText(info.upload_date+" • "); } + imageLoader.displayImage(info.thumbnail_url, holder.itemThumbnailView, displayImageOptions); + return convertView; } private class ViewHolder { public ImageView itemThumbnailView; - public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView; + public TextView itemVideoTitleView, itemUploaderView, itemDurationView, itemUploadDateView, itemViewCountView; + } + + private String shortViewCount(Long view_count){ + if(view_count >= 1000000000){ + return Long.toString(view_count/1000000000)+"B views"; + }else if(view_count>=1000000){ + return Long.toString(view_count/1000000)+"M views"; + }else if(view_count>=1000){ + return Long.toString(view_count/1000)+"K views"; + }else { + return Long.toString(view_count)+" views"; + } } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index daa7719c0..ed87235c5 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -2,7 +2,7 @@ package org.schabi.newpipe; import android.app.Activity; import android.content.Intent; -import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Point; @@ -20,11 +20,13 @@ import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; @@ -32,16 +34,19 @@ import android.view.MenuItem; import android.widget.Toast; import java.io.IOException; -import java.net.URL; -import java.nio.charset.MalformedInputException; + +import com.nostra13.universalimageloader.core.DisplayImageOptions; +import com.nostra13.universalimageloader.core.ImageLoader; +import com.nostra13.universalimageloader.core.assist.FailReason; +import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; + import java.util.ArrayList; import java.util.Vector; -import org.schabi.newpipe.crawler.CrawlingException; import org.schabi.newpipe.crawler.ParsingException; +import org.schabi.newpipe.crawler.ServiceList; import org.schabi.newpipe.crawler.VideoPreviewInfo; import org.schabi.newpipe.crawler.VideoExtractor; -import org.schabi.newpipe.crawler.ServiceList; import org.schabi.newpipe.crawler.StreamingService; import org.schabi.newpipe.crawler.VideoInfo; import org.schabi.newpipe.crawler.services.youtube.YoutubeVideoExtractor; @@ -91,6 +96,12 @@ public class VideoItemDetailFragment extends Fragment { private FloatingActionButton playVideoButton; private final Point initialThumbnailPos = new Point(0, 0); + + private ImageLoader imageLoader = ImageLoader.getInstance(); + private DisplayImageOptions displayImageOptions = + new DisplayImageOptions.Builder().cacheInMemory(true).build(); + + public interface OnInvokeCreateOptionsMenuListener { void createOptionsMenu(); } @@ -113,31 +124,8 @@ public class VideoItemDetailFragment extends Fragment { try { videoExtractor = service.getExtractorInstance(videoUrl, new Downloader()); VideoInfo videoInfo = VideoInfo.getVideoInfo(videoExtractor, new Downloader()); + h.post(new VideoResultReturnedRunnable(videoInfo)); - h.post(new SetThumbnailRunnable( - //todo: make bitmaps not bypass tor - BitmapFactory.decodeStream( - new URL(videoInfo.thumbnail_url) - .openConnection() - .getInputStream()), - SetThumbnailRunnable.VIDEO_THUMBNAIL)); - h.post(new SetThumbnailRunnable( - BitmapFactory.decodeStream( - new URL(videoInfo.uploader_thumbnail_url) - .openConnection() - .getInputStream()), - SetThumbnailRunnable.CHANNEL_THUMBNAIL)); - if (showNextVideoItem) { - h.post(new SetThumbnailRunnable( - BitmapFactory.decodeStream( - new URL(videoInfo.nextVideo.thumbnail_url) - .openConnection() - .getInputStream()), - SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL)); - } - } catch (MalformedInputException e) { - postNewErrorToast(h, R.string.could_not_load_thumbnails); - e.printStackTrace(); } catch (IOException e) { postNewErrorToast(h, R.string.network_error); e.printStackTrace(); @@ -186,52 +174,22 @@ public class VideoItemDetailFragment extends Fragment { } } - private class SetThumbnailRunnable implements Runnable { - public static final int VIDEO_THUMBNAIL = 1; - public static final int CHANNEL_THUMBNAIL = 2; - public static final int NEXT_VIDEO_THUMBNAIL = 3; - private final Bitmap thumbnail; - private final int thumbnailId; - public SetThumbnailRunnable(Bitmap thumbnail, int id) { - this.thumbnail = thumbnail; - this.thumbnailId = id; - } + private class ThumbnailLoadingListener implements ImageLoadingListener { @Override - public void run() { - updateThumbnail(thumbnail, thumbnailId); + public void onLoadingStarted(String imageUri, View view) {} + + @Override + public void onLoadingFailed(String imageUri, View view, FailReason failReason) { + Toast.makeText(VideoItemDetailFragment.this.getActivity(), + R.string.could_not_load_thumbnails, Toast.LENGTH_LONG).show(); + failReason.getCause().printStackTrace(); } - } - private void updateThumbnail(Bitmap thumbnail, int id) { - Activity a = getActivity(); - ImageView thumbnailView; - try { - switch (id) { - case SetThumbnailRunnable.VIDEO_THUMBNAIL: - thumbnailView = (ImageView) a.findViewById(R.id.detailThumbnailView); - actionBarHandler.setSetVideoThumbnail(thumbnail); - break; - case SetThumbnailRunnable.CHANNEL_THUMBNAIL: - thumbnailView = (ImageView) a.findViewById(R.id.detailUploaderThumbnailView); - break; - case SetThumbnailRunnable.NEXT_VIDEO_THUMBNAIL: - FrameLayout nextVideoFrame = (FrameLayout) a.findViewById(R.id.detailNextVideoFrame); - thumbnailView = (ImageView) nextVideoFrame.findViewById(R.id.itemThumbnailView); - currentVideoInfo.nextVideo.thumbnail = thumbnail; - break; - default: - Log.d(TAG, "Error: Thumbnail id not known"); - return; - } + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {} - if (thumbnailView != null) { - thumbnailView.setImageBitmap(thumbnail); - } - - } catch (java.lang.NullPointerException e) { - // Not good program design, I know. :/ - Log.w(TAG, "updateThumbnail(): Fragment closed before thread ended work"); - } + @Override + public void onLoadingCancelled(String imageUri, View view) {} } private void updateInfo(VideoInfo info) { @@ -241,36 +199,62 @@ public class VideoItemDetailFragment extends Fragment { VideoInfoItemViewCreator videoItemViewCreator = new VideoInfoItemViewCreator(LayoutInflater.from(getActivity())); - RelativeLayout textContentLayout = (RelativeLayout) activity.findViewById(R.id.detailTextContentLayout); - TextView videoTitleView = (TextView) activity.findViewById(R.id.detailVideoTitleView); + RelativeLayout textContentLayout = + (RelativeLayout) activity.findViewById(R.id.detailTextContentLayout); + final 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 thumbsDownView = + (TextView) activity.findViewById(R.id.detailThumbsDownCountView); TextView uploadDateView = (TextView) activity.findViewById(R.id.detailUploadDateView); TextView descriptionView = (TextView) activity.findViewById(R.id.detailDescriptionView); - FrameLayout nextVideoFrame = (FrameLayout) activity.findViewById(R.id.detailNextVideoFrame); + FrameLayout nextVideoFrame = + (FrameLayout) activity.findViewById(R.id.detailNextVideoFrame); RelativeLayout nextVideoRootFrame = (RelativeLayout) activity.findViewById(R.id.detailNextVideoRootLayout); - - progressBar.setVisibility(View.GONE); - - + Button nextVideoButton = (Button) activity.findViewById(R.id.detailNextVideoButton); + TextView similarTitle = (TextView) activity.findViewById(R.id.detailSimilarTitle); + View topView = activity.findViewById(R.id.detailTopView); View nextVideoView = videoItemViewCreator .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo, getContext()); + + progressBar.setVisibility(View.GONE); nextVideoFrame.addView(nextVideoView); - - Button nextVideoButton = (Button) activity.findViewById(R.id.detailNextVideoButton); - Button similarVideosButton = (Button) activity.findViewById(R.id.detailShowSimilarButton); + initThumbnailViews(info, nextVideoFrame); textContentLayout.setVisibility(View.VISIBLE); playVideoButton.setVisibility(View.VISIBLE); if (!showNextVideoItem) { nextVideoRootFrame.setVisibility(View.GONE); - similarVideosButton.setVisibility(View.GONE); + similarTitle.setVisibility(View.GONE); } + videoTitleView.setText(info.title); + + topView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == android.view.MotionEvent.ACTION_UP) { + ImageView arrow = (ImageView) activity.findViewById(R.id.toggleDescriptionView); + View extra = activity.findViewById(R.id.detailExtraView); + if (extra.getVisibility() == View.VISIBLE) { + extra.setVisibility(View.GONE); + arrow.setImageResource(R.drawable.arrow_down); + } else { + extra.setVisibility(View.VISIBLE); + arrow.setImageResource(R.drawable.arrow_up); + } + } + return true; + } + }); + + uploaderView.setText(info.uploader); + actionBarHandler.setChannelName(info.uploader); + videoTitleView.setText(info.title); uploaderView.setText(info.uploader); actionBarHandler.setChannelName(info.uploader); @@ -314,12 +298,13 @@ public class VideoItemDetailFragment extends Fragment { VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); */ detailIntent.putExtra( VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url); - detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId); startActivity(detailIntent); } }); + textContentLayout.setVisibility(View.VISIBLE); + initSimilarVideos(videoItemViewCreator); if(autoPlayEnabled) { actionBarHandler.playVideo(); @@ -330,6 +315,76 @@ public class VideoItemDetailFragment extends Fragment { } } + private void initThumbnailViews(VideoInfo info, View nextVideoFrame) { + ImageView videoThumbnailView = (ImageView) activity.findViewById(R.id.detailThumbnailView); + ImageView uploaderThumb + = (ImageView) activity.findViewById(R.id.detailUploaderThumbnailView); + ImageView nextVideoThumb = + (ImageView) nextVideoFrame.findViewById(R.id.itemThumbnailView); + + imageLoader.displayImage(info.thumbnail_url, videoThumbnailView, + displayImageOptions, new ImageLoadingListener() { + @Override + public void onLoadingStarted(String imageUri, View view) {} + + @Override + public void onLoadingFailed(String imageUri, View view, FailReason failReason) { + Toast.makeText(VideoItemDetailFragment.this.getActivity(), + R.string.could_not_load_thumbnails, Toast.LENGTH_LONG).show(); + failReason.getCause().printStackTrace(); + } + + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { + actionBarHandler.setVideoThumbnail(loadedImage); + } + + @Override + public void onLoadingCancelled(String imageUri, View view) {} + }); + imageLoader.displayImage(info.uploader_thumbnail_url, + uploaderThumb, displayImageOptions, new ThumbnailLoadingListener()); + imageLoader.displayImage(info.nextVideo.thumbnail_url, + nextVideoThumb, displayImageOptions, new ThumbnailLoadingListener()); + } + + private void initSimilarVideos(VideoInfoItemViewCreator videoItemViewCreator) { + LinearLayout similarLayout = (LinearLayout) activity.findViewById(R.id.similarVideosView); + ArrayList similar = new ArrayList<>(currentVideoInfo.relatedVideos); + for (final VideoPreviewInfo item : similar) { + View similarView = videoItemViewCreator + .getViewFromVideoInfoItem(null, similarLayout, item, getContext()); + + similarView.setClickable(true); + similarView.setFocusable(true); + int[] attrs = new int[]{R.attr.selectableItemBackground}; + TypedArray typedArray = activity.obtainStyledAttributes(attrs); + int backgroundResource = typedArray.getResourceId(0, 0); + similarView.setBackgroundResource(backgroundResource); + typedArray.recycle(); + + similarView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP) { + Intent detailIntent = new Intent(activity, VideoItemDetailActivity.class); + detailIntent.putExtra(VideoItemDetailFragment.VIDEO_URL, item.webpage_url); + detailIntent.putExtra( + VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId); + startActivity(detailIntent); + return true; + } + return false; + } + }); + + similarLayout.addView(similarView); + ImageView rthumb = (ImageView)similarView.findViewById(R.id.itemThumbnailView); + imageLoader.displayImage(item.thumbnail_url, rthumb, + displayImageOptions, new ThumbnailLoadingListener()); + } + } + private void onErrorBlockedByGema() { Button backgroundButton = (Button) activity.findViewById(R.id.detailVideoThumbnailWindowBackgroundButton); @@ -438,21 +493,6 @@ public class VideoItemDetailFragment extends Fragment { } }); - 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); - //todo: find more elegant way to do this - converting from List to ArrayList sucks - ArrayList toParcel = new ArrayList<>(currentVideoInfo.relatedVideos); - //why oh why does the parcelable array put method have to be so damn specific - // about the class of its argument? - //why not a List? - intent.putParcelableArrayListExtra(VideoItemListActivity.VIDEO_INFO_ITEMS, toParcel); - activity.startActivity(intent); - } - }); - // todo: Fix this workaround (probably with a better design), so that older android // versions don't have problems rendering the thumbnail right. if(Build.VERSION.SDK_INT >= 18) { @@ -461,7 +501,8 @@ public class VideoItemDetailFragment extends Fragment { // This is used to synchronize the thumbnailWindowButton and the playVideoButton // inside the ScrollView with the actual size of the thumbnail. @Override - public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { + public void onLayoutChange(View v, int left, int top, int right, int bottom, + int oldLeft, int oldTop, int oldRight, int oldBottom) { RelativeLayout.LayoutParams newWindowLayoutParams = (RelativeLayout.LayoutParams) thumbnailWindowLayout.getLayoutParams(); newWindowLayoutParams.height = bottom - top; diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 479a4820d..cf8a5a08c 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -61,8 +61,6 @@ public class VideoItemListFragment extends ListFragment { private Thread searchThread = null; private SearchRunnable searchRunnable = null; - private Thread loadThumbsThread = null; - private LoadThumbsRunnable loadThumbsRunnable = null; // used to track down if results posted by threads ar still valid private int currentRequestId = -1; private ListView list; @@ -130,7 +128,8 @@ public class VideoItemListFragment extends ListFragment { } } } - +/* +<<< private class LoadThumbsRunnable implements Runnable { private final Vector thumbnailUrlList = new Vector<>(); private final Vector downloadedList; @@ -187,6 +186,9 @@ public class VideoItemListFragment extends ListFragment { } } +======= +>>>>>>> 6d1b4652fc98e5c2d5e19b0f98ba38a731137a70 +*/ public void present(List videoList) { mode = PRESENT_VIDEOS_MODE; setListShown(true); @@ -246,10 +248,6 @@ public class VideoItemListFragment extends ListFragment { try { videoListAdapter.addVideoList(list); terminateThreads(); - loadThumbsRunnable = new LoadThumbsRunnable(videoListAdapter.getVideoList(), - videoListAdapter.getDownloadedThumbnailList(), currentRequestId); - loadThumbsThread = new Thread(loadThumbsRunnable); - loadThumbsThread.start(); } catch(java.lang.IllegalStateException e) { Log.w(TAG, "Trying to set value while activity doesn't exist anymore."); } catch(Exception e) { @@ -260,14 +258,6 @@ public class VideoItemListFragment extends ListFragment { } private void terminateThreads() { - if(loadThumbsRunnable != null && loadThumbsRunnable.isRunning()) { - loadThumbsRunnable.terminate(); - try { - loadThumbsThread.join(); - } catch(Exception e) { - e.printStackTrace(); - } - } if(searchThread != null) { searchRunnable.terminate(); // No need to join, since we don't really terminate the thread. We just demand diff --git a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java index 54ff763f0..7077810ad 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java @@ -1,7 +1,6 @@ package org.schabi.newpipe; import android.content.Context; -import android.graphics.Bitmap; import android.support.v4.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; @@ -38,7 +37,6 @@ class VideoListAdapter extends BaseAdapter { private final Context context; private final VideoInfoItemViewCreator viewCreator; private Vector videoList = new Vector<>(); - private Vector downloadedThumbnailList = new Vector<>(); private final ListView listView; public VideoListAdapter(Context context, VideoItemListFragment videoListFragment) { @@ -51,15 +49,11 @@ class VideoListAdapter extends BaseAdapter { public void addVideoList(List videos) { videoList.addAll(videos); - for(int i = 0; i < videos.size(); i++) { - downloadedThumbnailList.add(false); - } notifyDataSetChanged(); } public void clearVideoList() { videoList = new Vector<>(); - downloadedThumbnailList = new Vector<>(); notifyDataSetChanged(); } @@ -67,20 +61,6 @@ class VideoListAdapter extends BaseAdapter { return videoList; } - public void updateDownloadedThumbnailList(int index) { - downloadedThumbnailList.set(index, true); - } - - public Vector getDownloadedThumbnailList() { - return downloadedThumbnailList; - } - - public void setThumbnail(int index, Bitmap thumbnail) { - videoList.get(index).thumbnail = thumbnail; - downloadedThumbnailList.set(index, true); - notifyDataSetChanged(); - } - @Override public int getCount() { return videoList.size(); diff --git a/app/src/main/java/org/schabi/newpipe/crawler/services/youtube/YoutubeSearchEngine.java b/app/src/main/java/org/schabi/newpipe/crawler/services/youtube/YoutubeSearchEngine.java index a6d4857c1..dca9caa26 100644 --- a/app/src/main/java/org/schabi/newpipe/crawler/services/youtube/YoutubeSearchEngine.java +++ b/app/src/main/java/org/schabi/newpipe/crawler/services/youtube/YoutubeSearchEngine.java @@ -122,6 +122,15 @@ public class YoutubeSearchEngine implements SearchEngine { resultItem.upload_date = item.select("div[class=\"yt-lockup-meta\"]").first() .select("li").first() .text(); + + //todo: test against view_count + String viewCountInfo = item.select("div[class=\"yt-lockup-meta\"]").first() + .select("li").get(1) + .text(); + viewCountInfo = viewCountInfo.substring(0, viewCountInfo.indexOf(' ')); + viewCountInfo = viewCountInfo.replaceAll("[,.]", ""); + resultItem.view_count = Long.parseLong(viewCountInfo); + Element te = item.select("div[class=\"yt-thumb video-thumb\"]").first() .select("img").first(); resultItem.thumbnail_url = te.attr("abs:src"); diff --git a/app/src/main/res/drawable-nodpi/arrow_down.png b/app/src/main/res/drawable-nodpi/arrow_down.png new file mode 100644 index 0000000000000000000000000000000000000000..f968ab32bcc5aef96623ae04b6133f9619ba8b0a GIT binary patch literal 3297 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/arrow_up.png b/app/src/main/res/drawable-nodpi/arrow_up.png new file mode 100644 index 0000000000000000000000000000000000000000..e5081691a81e485b3cc1da41439483b5b0cfb0da GIT binary patch literal 3271 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 FV1hE<0f+zq literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout-v18/fragment_videoitem_detail.xml b/app/src/main/res/layout-v18/fragment_videoitem_detail.xml deleted file mode 100644 index cbb5652ca..000000000 --- a/app/src/main/res/layout-v18/fragment_videoitem_detail.xml +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - - - - -