commit
e69c45a246
33 changed files with 1824 additions and 570 deletions
|
@ -57,7 +57,7 @@ dependencies {
|
|||
exclude module: 'support-annotations'
|
||||
})
|
||||
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:79b0a19d1af'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:8de53111d9'
|
||||
|
||||
testImplementation 'junit:junit:4.12'
|
||||
testImplementation 'org.mockito:mockito-core:2.23.0'
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package android.support.design.widget;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.animation.AnimationUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
// check this https://github.com/ToDou/appbarlayout-spring-behavior/blob/master/appbarspring/src/main/java/android/support/design/widget/AppBarFlingFixBehavior.java
|
||||
public final class FlingBehavior extends AppBarLayout.Behavior {
|
||||
|
||||
private ValueAnimator mOffsetAnimator;
|
||||
private static final int MAX_OFFSET_ANIMATION_DURATION = 600; // ms
|
||||
|
||||
public FlingBehavior() {
|
||||
}
|
||||
|
||||
public FlingBehavior(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed, int type) {
|
||||
if (dy != 0) {
|
||||
int val = child.getBottom();
|
||||
if (val != 0) {
|
||||
int min, max;
|
||||
if (dy < 0) {
|
||||
// We're scrolling down
|
||||
} else {
|
||||
// We're scrolling up
|
||||
if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) {
|
||||
mOffsetAnimator.cancel();
|
||||
}
|
||||
min = -child.getUpNestedPreScrollRange();
|
||||
max = 0;
|
||||
consumed[1] = scroll(coordinatorLayout, child, dy, min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedPreFling(@NonNull CoordinatorLayout coordinatorLayout, @NonNull AppBarLayout child, @NonNull View target, float velocityX, float velocityY) {
|
||||
|
||||
if (velocityY != 0) {
|
||||
if (velocityY < 0) {
|
||||
// We're flinging down
|
||||
int val = child.getBottom();
|
||||
if (val != 0) {
|
||||
final int targetScroll =
|
||||
+child.getDownNestedPreScrollRange();
|
||||
animateOffsetTo(coordinatorLayout, child, targetScroll, velocityY);
|
||||
}
|
||||
|
||||
} else {
|
||||
// We're flinging up
|
||||
int val = child.getBottom();
|
||||
if (val != 0) {
|
||||
final int targetScroll = -child.getUpNestedPreScrollRange();
|
||||
if (getTopBottomOffsetForScrollingSibling() > targetScroll) {
|
||||
animateOffsetTo(coordinatorLayout, child, targetScroll, velocityY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
|
||||
}
|
||||
|
||||
private void animateOffsetTo(final CoordinatorLayout coordinatorLayout,
|
||||
final AppBarLayout child, final int offset, float velocity) {
|
||||
final int distance = Math.abs(getTopBottomOffsetForScrollingSibling() - offset);
|
||||
|
||||
final int duration;
|
||||
velocity = Math.abs(velocity);
|
||||
if (velocity > 0) {
|
||||
duration = 3 * Math.round(1000 * (distance / velocity));
|
||||
} else {
|
||||
final float distanceRatio = (float) distance / child.getHeight();
|
||||
duration = (int) ((distanceRatio + 1) * 150);
|
||||
}
|
||||
|
||||
animateOffsetWithDuration(coordinatorLayout, child, offset, duration);
|
||||
}
|
||||
|
||||
private void animateOffsetWithDuration(final CoordinatorLayout coordinatorLayout,
|
||||
final AppBarLayout child, final int offset, final int duration) {
|
||||
final int currentOffset = getTopBottomOffsetForScrollingSibling();
|
||||
if (currentOffset == offset) {
|
||||
if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) {
|
||||
mOffsetAnimator.cancel();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOffsetAnimator == null) {
|
||||
mOffsetAnimator = new ValueAnimator();
|
||||
mOffsetAnimator.setInterpolator(AnimationUtils.DECELERATE_INTERPOLATOR);
|
||||
mOffsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animator) {
|
||||
setHeaderTopBottomOffset(coordinatorLayout, child,
|
||||
(Integer) animator.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mOffsetAnimator.cancel();
|
||||
}
|
||||
|
||||
mOffsetAnimator.setDuration(Math.min(duration, MAX_OFFSET_ANIMATION_DURATION));
|
||||
mOffsetAnimator.setIntValues(currentOffset, offset);
|
||||
mOffsetAnimator.start();
|
||||
}
|
||||
}
|
|
@ -3,18 +3,24 @@ package org.schabi.newpipe;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.schabi.newpipe.extractor.DownloadRequest;
|
||||
import org.schabi.newpipe.extractor.DownloadResponse;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
import org.schabi.newpipe.extractor.utils.Localization;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
|
@ -139,13 +145,16 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|||
|
||||
private ResponseBody getBody(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
|
||||
final Request.Builder requestBuilder = new Request.Builder()
|
||||
.method("GET", null).url(siteUrl)
|
||||
.addHeader("User-Agent", USER_AGENT);
|
||||
.method("GET", null).url(siteUrl);
|
||||
|
||||
for (Map.Entry<String, String> header : customProperties.entrySet()) {
|
||||
requestBuilder.addHeader(header.getKey(), header.getValue());
|
||||
}
|
||||
|
||||
if (!customProperties.containsKey("User-Agent")) {
|
||||
requestBuilder.header("User-Agent", USER_AGENT);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mCookies)) {
|
||||
requestBuilder.addHeader("Cookie", mCookies);
|
||||
}
|
||||
|
@ -177,4 +186,96 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
|
|||
public String download(String siteUrl) throws IOException, ReCaptchaException {
|
||||
return download(siteUrl, Collections.emptyMap());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DownloadResponse get(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException {
|
||||
final Request.Builder requestBuilder = new Request.Builder()
|
||||
.method("GET", null).url(siteUrl);
|
||||
|
||||
Map<String, List<String>> requestHeaders = request.getRequestHeaders();
|
||||
// set custom headers in request
|
||||
for (Map.Entry<String, List<String>> pair : requestHeaders.entrySet()) {
|
||||
for(String value : pair.getValue()){
|
||||
requestBuilder.addHeader(pair.getKey(), value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!requestHeaders.containsKey("User-Agent")) {
|
||||
requestBuilder.header("User-Agent", USER_AGENT);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mCookies)) {
|
||||
requestBuilder.addHeader("Cookie", mCookies);
|
||||
}
|
||||
|
||||
final Request okRequest = requestBuilder.build();
|
||||
final Response response = client.newCall(okRequest).execute();
|
||||
final ResponseBody body = response.body();
|
||||
|
||||
if (response.code() == 429) {
|
||||
throw new ReCaptchaException("reCaptcha Challenge requested");
|
||||
}
|
||||
|
||||
if (body == null) {
|
||||
response.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DownloadResponse(body.string(), response.headers().toMultimap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadResponse get(String siteUrl) throws IOException, ReCaptchaException {
|
||||
return get(siteUrl, DownloadRequest.emptyRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadResponse post(String siteUrl, DownloadRequest request) throws IOException, ReCaptchaException {
|
||||
|
||||
Map<String, List<String>> requestHeaders = request.getRequestHeaders();
|
||||
if(null == requestHeaders.get("Content-Type") || requestHeaders.get("Content-Type").isEmpty()){
|
||||
// content type header is required. maybe throw an exception here
|
||||
return null;
|
||||
}
|
||||
|
||||
String contentType = requestHeaders.get("Content-Type").get(0);
|
||||
|
||||
RequestBody okRequestBody = null;
|
||||
if(null != request.getRequestBody()){
|
||||
okRequestBody = RequestBody.create(MediaType.parse(contentType), request.getRequestBody());
|
||||
}
|
||||
final Request.Builder requestBuilder = new Request.Builder()
|
||||
.method("POST", okRequestBody).url(siteUrl);
|
||||
|
||||
// set custom headers in request
|
||||
for (Map.Entry<String, List<String>> pair : requestHeaders.entrySet()) {
|
||||
for(String value : pair.getValue()){
|
||||
requestBuilder.addHeader(pair.getKey(), value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!requestHeaders.containsKey("User-Agent")) {
|
||||
requestBuilder.header("User-Agent", USER_AGENT);
|
||||
}
|
||||
|
||||
if (!TextUtils.isEmpty(mCookies)) {
|
||||
requestBuilder.addHeader("Cookie", mCookies);
|
||||
}
|
||||
|
||||
final Request okRequest = requestBuilder.build();
|
||||
final Response response = client.newCall(okRequest).execute();
|
||||
final ResponseBody body = response.body();
|
||||
|
||||
if (response.code() == 429) {
|
||||
throw new ReCaptchaException("reCaptcha Challenge requested");
|
||||
}
|
||||
|
||||
if (body == null) {
|
||||
response.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
return new DownloadResponse(body.string(), response.headers().toMultimap());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package org.schabi.newpipe.fragments.detail;
|
||||
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class TabAdaptor extends FragmentPagerAdapter {
|
||||
|
||||
private final List<Fragment> mFragmentList = new ArrayList<>();
|
||||
private final List<String> mFragmentTitleList = new ArrayList<>();
|
||||
private final FragmentManager fragmentManager;
|
||||
|
||||
public TabAdaptor(FragmentManager fm) {
|
||||
super(fm);
|
||||
this.fragmentManager = fm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return mFragmentList.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFragmentList.size();
|
||||
}
|
||||
|
||||
public void addFragment(Fragment fragment, String title) {
|
||||
mFragmentList.add(fragment);
|
||||
mFragmentTitleList.add(title);
|
||||
}
|
||||
|
||||
public void clearAllItems() {
|
||||
mFragmentList.clear();
|
||||
mFragmentTitleList.clear();
|
||||
}
|
||||
|
||||
public void removeItem(int position){
|
||||
mFragmentList.remove(position == 0 ? 0 : position - 1);
|
||||
mFragmentTitleList.remove(position == 0 ? 0 : position - 1);
|
||||
}
|
||||
|
||||
public void updateItem(int position, Fragment fragment){
|
||||
mFragmentList.set(position, fragment);
|
||||
}
|
||||
|
||||
public void updateItem(String title, Fragment fragment){
|
||||
int index = mFragmentTitleList.indexOf(title);
|
||||
if(index != -1){
|
||||
updateItem(index, fragment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPosition(Object object) {
|
||||
if (mFragmentList.contains(object)) return mFragmentList.indexOf(object);
|
||||
else return POSITION_NONE;
|
||||
}
|
||||
|
||||
public void notifyDataSetUpdate(){
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
||||
fragmentManager.beginTransaction().remove((Fragment) object).commitNowAllowingStateLoss();
|
||||
}
|
||||
|
||||
}
|
|
@ -10,11 +10,13 @@ import android.os.Build;
|
|||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.FloatRange;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
@ -25,7 +27,6 @@ import android.text.method.LinkMovementMethod;
|
|||
import android.text.util.Linkify;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -33,19 +34,15 @@ import android.view.MenuItem;
|
|||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.nirhart.parallaxscroll.views.ParallaxScrollView;
|
||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
||||
|
@ -57,6 +54,7 @@ import org.schabi.newpipe.extractor.InfoItem;
|
|||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.ServiceList;
|
||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
|
@ -64,21 +62,21 @@ import org.schabi.newpipe.extractor.stream.Stream;
|
|||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.fragments.BackPressable;
|
||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
|
||||
import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment;
|
||||
import org.schabi.newpipe.info_list.InfoItemDialog;
|
||||
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||
import org.schabi.newpipe.player.MainVideoPlayer;
|
||||
import org.schabi.newpipe.player.PopupVideoPlayer;
|
||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||
|
@ -86,11 +84,9 @@ import org.schabi.newpipe.util.InfoCache;
|
|||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.Localization;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.OnClickGesture;
|
||||
import org.schabi.newpipe.util.PermissionHelper;
|
||||
import org.schabi.newpipe.util.StreamItemAdapter;
|
||||
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
@ -105,6 +101,7 @@ import io.reactivex.disposables.CompositeDisposable;
|
|||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
public class VideoDetailFragment
|
||||
|
@ -115,27 +112,27 @@ public class VideoDetailFragment
|
|||
View.OnLongClickListener {
|
||||
public static final String AUTO_PLAY = "auto_play";
|
||||
|
||||
// Amount of videos to show on start
|
||||
private static final int INITIAL_RELATED_VIDEOS = 8;
|
||||
|
||||
private InfoItemBuilder infoItemBuilder = null;
|
||||
|
||||
private int updateFlags = 0;
|
||||
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
||||
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
|
||||
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
|
||||
private static final int COMMENTS_UPDATE_FLAG = 0x4;
|
||||
|
||||
private boolean autoPlayEnabled;
|
||||
private boolean showRelatedStreams;
|
||||
private boolean wasRelatedStreamsExpanded = false;
|
||||
private boolean showComments;
|
||||
|
||||
@State protected int serviceId = Constants.NO_SERVICE_ID;
|
||||
@State protected String name;
|
||||
@State protected String url;
|
||||
@State
|
||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||
@State
|
||||
protected String name;
|
||||
@State
|
||||
protected String url;
|
||||
|
||||
private StreamInfo currentInfo;
|
||||
private Disposable currentWorker;
|
||||
@NonNull private CompositeDisposable disposables = new CompositeDisposable();
|
||||
@NonNull
|
||||
private CompositeDisposable disposables = new CompositeDisposable();
|
||||
|
||||
private List<VideoStream> sortedVideoStreams;
|
||||
private int selectedVideoStreamIndex = -1;
|
||||
|
@ -148,7 +145,6 @@ public class VideoDetailFragment
|
|||
|
||||
private Spinner spinnerToolbar;
|
||||
|
||||
private ParallaxScrollView parallaxScrollRootView;
|
||||
private LinearLayout contentRootLayoutHiding;
|
||||
|
||||
private View thumbnailBackgroundButton;
|
||||
|
@ -157,7 +153,6 @@ public class VideoDetailFragment
|
|||
|
||||
private View videoTitleRoot;
|
||||
private TextView videoTitleTextView;
|
||||
@Nullable
|
||||
private ImageView videoTitleToggleArrow;
|
||||
private TextView videoCountView;
|
||||
|
||||
|
@ -182,10 +177,14 @@ public class VideoDetailFragment
|
|||
private ImageView thumbsDownImageView;
|
||||
private TextView thumbsDisabledTextView;
|
||||
|
||||
private TextView nextStreamTitle;
|
||||
private LinearLayout relatedStreamRootLayout;
|
||||
private LinearLayout relatedStreamsView;
|
||||
private ImageButton relatedStreamExpandButton;
|
||||
private static final String COMMENTS_TAB_TAG = "COMMENTS";
|
||||
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
|
||||
|
||||
private AppBarLayout appBarLayout;
|
||||
private ViewPager viewPager;
|
||||
private TabAdaptor pageAdapter;
|
||||
private TabLayout tabLayout;
|
||||
private FrameLayout relatedStreamsLayout;
|
||||
|
||||
|
||||
/*////////////////////////////////////////////////////////////////////////*/
|
||||
|
@ -201,12 +200,17 @@ public class VideoDetailFragment
|
|||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
public void
|
||||
onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.getBoolean(getString(R.string.show_next_video_key), true);
|
||||
|
||||
showComments = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.getBoolean(getString(R.string.show_comments_key), true);
|
||||
|
||||
PreferenceManager.getDefaultSharedPreferences(activity)
|
||||
.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
@ -228,14 +232,16 @@ public class VideoDetailFragment
|
|||
|
||||
if (updateFlags != 0) {
|
||||
if (!isLoading.get() && currentInfo != null) {
|
||||
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) initRelatedVideos(currentInfo);
|
||||
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) startLoading(false);
|
||||
if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo);
|
||||
if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) startLoading(false);
|
||||
}
|
||||
|
||||
if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0
|
||||
&& menu != null) {
|
||||
updateMenuItemVisibility();
|
||||
}
|
||||
|
||||
updateFlags = 0;
|
||||
}
|
||||
|
||||
|
@ -292,6 +298,9 @@ public class VideoDetailFragment
|
|||
updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG;
|
||||
} else if (key.equals(getString(R.string.show_play_with_kodi_key))) {
|
||||
updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG;
|
||||
} else if (key.equals(getString(R.string.show_comments_key))) {
|
||||
showComments = sharedPreferences.getBoolean(key, true);
|
||||
updateFlags |= COMMENTS_UPDATE_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,7 +310,6 @@ public class VideoDetailFragment
|
|||
|
||||
private static final String INFO_KEY = "info_key";
|
||||
private static final String STACK_KEY = "stack_key";
|
||||
private static final String WAS_RELATED_EXPANDED_KEY = "was_related_expanded_key";
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
|
@ -310,10 +318,6 @@ public class VideoDetailFragment
|
|||
// Check if the next video label and video is visible,
|
||||
// if it is, include the two elements in the next check
|
||||
int nextCount = currentInfo != null && currentInfo.getNextVideo() != null ? 2 : 0;
|
||||
if (relatedStreamsView != null
|
||||
&& relatedStreamsView.getChildCount() > INITIAL_RELATED_VIDEOS + nextCount) {
|
||||
outState.putSerializable(WAS_RELATED_EXPANDED_KEY, true);
|
||||
}
|
||||
|
||||
if (!isLoading.get() && currentInfo != null && isVisible()) {
|
||||
outState.putSerializable(INFO_KEY, currentInfo);
|
||||
|
@ -326,12 +330,11 @@ public class VideoDetailFragment
|
|||
protected void onRestoreInstanceState(@NonNull Bundle savedState) {
|
||||
super.onRestoreInstanceState(savedState);
|
||||
|
||||
wasRelatedStreamsExpanded = savedState.getBoolean(WAS_RELATED_EXPANDED_KEY, false);
|
||||
Serializable serializable = savedState.getSerializable(INFO_KEY);
|
||||
if (serializable instanceof StreamInfo) {
|
||||
//noinspection unchecked
|
||||
currentInfo = (StreamInfo) serializable;
|
||||
InfoCache.getInstance().putInfo(serviceId, url, currentInfo);
|
||||
InfoCache.getInstance().putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM);
|
||||
}
|
||||
|
||||
serializable = savedState.getSerializable(STACK_KEY);
|
||||
|
@ -339,6 +342,7 @@ public class VideoDetailFragment
|
|||
//noinspection unchecked
|
||||
stack.addAll((Collection<? extends StackItem>) serializable);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -394,9 +398,6 @@ public class VideoDetailFragment
|
|||
case R.id.detail_title_root_layout:
|
||||
toggleTitleAndDescription();
|
||||
break;
|
||||
case R.id.detail_related_streams_expand:
|
||||
toggleExpandRelatedVideos(currentInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,44 +421,17 @@ public class VideoDetailFragment
|
|||
}
|
||||
|
||||
private void toggleTitleAndDescription() {
|
||||
if (videoTitleToggleArrow != null) { //it is null for tablets
|
||||
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
||||
videoTitleTextView.setMaxLines(1);
|
||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||
} else {
|
||||
videoTitleTextView.setMaxLines(10);
|
||||
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
|
||||
}
|
||||
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
||||
videoTitleTextView.setMaxLines(1);
|
||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||
} else {
|
||||
videoTitleTextView.setMaxLines(10);
|
||||
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleExpandRelatedVideos(StreamInfo info) {
|
||||
if (DEBUG) Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "]");
|
||||
if (!showRelatedStreams) return;
|
||||
|
||||
int nextCount = info.getNextVideo() != null ? 2 : 0;
|
||||
int initialCount = INITIAL_RELATED_VIDEOS + nextCount;
|
||||
|
||||
if (relatedStreamsView.getChildCount() > initialCount) {
|
||||
relatedStreamsView.removeViews(initialCount,
|
||||
relatedStreamsView.getChildCount() - (initialCount));
|
||||
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
|
||||
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = INITIAL_RELATED_VIDEOS; i < info.getRelatedStreams().size(); i++) {
|
||||
InfoItem item = info.getRelatedStreams().get(i);
|
||||
//Log.d(TAG, "i = " + i);
|
||||
relatedStreamsView.addView(infoItemBuilder.buildView(relatedStreamsView, item));
|
||||
}
|
||||
relatedStreamExpandButton.setImageDrawable(
|
||||
ContextCompat.getDrawable(activity,
|
||||
ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse)));
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Init
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
@ -467,8 +441,6 @@ public class VideoDetailFragment
|
|||
super.initViews(rootView, savedInstanceState);
|
||||
spinnerToolbar = activity.findViewById(R.id.toolbar).findViewById(R.id.toolbar_spinner);
|
||||
|
||||
parallaxScrollRootView = rootView.findViewById(R.id.detail_main_content);
|
||||
|
||||
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
|
||||
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
|
||||
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
|
||||
|
@ -504,32 +476,23 @@ public class VideoDetailFragment
|
|||
uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view);
|
||||
uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view);
|
||||
|
||||
relatedStreamRootLayout = rootView.findViewById(R.id.detail_related_streams_root_layout);
|
||||
nextStreamTitle = rootView.findViewById(R.id.detail_next_stream_title);
|
||||
relatedStreamsView = rootView.findViewById(R.id.detail_related_streams_view);
|
||||
appBarLayout = rootView.findViewById(R.id.appbarlayout);
|
||||
viewPager = rootView.findViewById(R.id.viewpager);
|
||||
pageAdapter = new TabAdaptor(getChildFragmentManager());
|
||||
viewPager.setAdapter(pageAdapter);
|
||||
tabLayout = rootView.findViewById(R.id.tablayout);
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
|
||||
relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand);
|
||||
relatedStreamsLayout = rootView.findViewById(R.id.relatedStreamsLayout);
|
||||
|
||||
infoItemBuilder = new InfoItemBuilder(activity);
|
||||
setHeightThumbnail();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initListeners() {
|
||||
super.initListeners();
|
||||
infoItemBuilder.setOnStreamSelectedListener(new OnClickGesture<StreamInfoItem>() {
|
||||
@Override
|
||||
public void selected(StreamInfoItem selectedItem) {
|
||||
selectAndLoadVideo(selectedItem.getServiceId(),
|
||||
selectedItem.getUrl(),
|
||||
selectedItem.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void held(StreamInfoItem selectedItem) {
|
||||
showStreamDialog(selectedItem);
|
||||
}
|
||||
});
|
||||
|
||||
videoTitleRoot.setOnClickListener(this);
|
||||
uploaderRootLayout.setOnClickListener(this);
|
||||
|
@ -539,7 +502,6 @@ public class VideoDetailFragment
|
|||
detailControlsAddToPlaylist.setOnClickListener(this);
|
||||
detailControlsDownload.setOnClickListener(this);
|
||||
detailControlsDownload.setOnLongClickListener(this);
|
||||
relatedStreamExpandButton.setOnClickListener(this);
|
||||
|
||||
detailControlsBackground.setLongClickable(true);
|
||||
detailControlsPopup.setLongClickable(true);
|
||||
|
@ -622,44 +584,6 @@ public class VideoDetailFragment
|
|||
}
|
||||
}
|
||||
|
||||
private void initRelatedVideos(StreamInfo info) {
|
||||
if (relatedStreamsView.getChildCount() > 0) relatedStreamsView.removeAllViews();
|
||||
|
||||
if (info.getNextVideo() != null && showRelatedStreams) {
|
||||
nextStreamTitle.setVisibility(View.VISIBLE);
|
||||
relatedStreamsView.addView(
|
||||
infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo()));
|
||||
relatedStreamsView.addView(getSeparatorView());
|
||||
setRelatedStreamsVisibility(View.VISIBLE);
|
||||
} else {
|
||||
nextStreamTitle.setVisibility(View.GONE);
|
||||
setRelatedStreamsVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (info.getRelatedStreams() != null
|
||||
&& !info.getRelatedStreams().isEmpty() && showRelatedStreams) {
|
||||
//long first = System.nanoTime(), each;
|
||||
int to = info.getRelatedStreams().size() >= INITIAL_RELATED_VIDEOS
|
||||
? INITIAL_RELATED_VIDEOS
|
||||
: info.getRelatedStreams().size();
|
||||
for (int i = 0; i < to; i++) {
|
||||
InfoItem item = info.getRelatedStreams().get(i);
|
||||
//each = System.nanoTime();
|
||||
relatedStreamsView.addView(infoItemBuilder.buildView(relatedStreamsView, item));
|
||||
//if (DEBUG) Log.d(TAG, "each took " + ((System.nanoTime() - each) / 1000000L) + "ms");
|
||||
}
|
||||
//if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms");
|
||||
|
||||
setRelatedStreamsVisibility(View.VISIBLE);
|
||||
relatedStreamExpandButton.setVisibility(View.VISIBLE);
|
||||
|
||||
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
|
||||
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
|
||||
} else {
|
||||
if (info.getNextVideo() == null) setRelatedStreamsVisibility(View.GONE);
|
||||
relatedStreamExpandButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Menu
|
||||
|
@ -693,7 +617,7 @@ public class VideoDetailFragment
|
|||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if(isLoading.get()) {
|
||||
if (isLoading.get()) {
|
||||
// if is still loading block menu
|
||||
return true;
|
||||
}
|
||||
|
@ -717,7 +641,7 @@ public class VideoDetailFragment
|
|||
NavigationHelper.playWithKore(activity, Uri.parse(
|
||||
url.replace("https", "http")));
|
||||
} catch (Exception e) {
|
||||
if(DEBUG) Log.i(TAG, "Failed to start kore", e);
|
||||
if (DEBUG) Log.i(TAG, "Failed to start kore", e);
|
||||
showInstallKoreDialog(activity);
|
||||
}
|
||||
return true;
|
||||
|
@ -731,7 +655,8 @@ public class VideoDetailFragment
|
|||
builder.setMessage(R.string.kore_not_found)
|
||||
.setPositiveButton(R.string.install, (DialogInterface dialog, int which) ->
|
||||
NavigationHelper.installKore(context))
|
||||
.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {});
|
||||
.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
|
@ -850,23 +775,16 @@ public class VideoDetailFragment
|
|||
setInitialData(info.getServiceId(), info.getUrl(), info.getName());
|
||||
pushToStack(serviceId, url, name);
|
||||
showLoading();
|
||||
initTabs();
|
||||
|
||||
Log.d(TAG, "prepareAndHandleInfo() called parallaxScrollRootView.getScrollY(): "
|
||||
+ parallaxScrollRootView.getScrollY());
|
||||
final boolean greaterThanThreshold = parallaxScrollRootView.getScrollY() > (int)
|
||||
(getResources().getDisplayMetrics().heightPixels * .1f);
|
||||
if (scrollToTop) appBarLayout.setExpanded(true, true);
|
||||
handleResult(info);
|
||||
showContent();
|
||||
|
||||
if (scrollToTop) parallaxScrollRootView.smoothScrollTo(0, 0);
|
||||
animateView(contentRootLayoutHiding,
|
||||
false,
|
||||
greaterThanThreshold ? 250 : 0, 0, () -> {
|
||||
handleResult(info);
|
||||
showContentWithAnimation(120, 0, .01f);
|
||||
});
|
||||
}
|
||||
|
||||
protected void prepareAndLoadInfo() {
|
||||
parallaxScrollRootView.smoothScrollTo(0, 0);
|
||||
appBarLayout.setExpanded(true, true);
|
||||
pushToStack(serviceId, url, name);
|
||||
startLoading(false);
|
||||
}
|
||||
|
@ -875,6 +793,7 @@ public class VideoDetailFragment
|
|||
public void startLoading(boolean forceLoad) {
|
||||
super.startLoading(forceLoad);
|
||||
|
||||
initTabs();
|
||||
currentInfo = null;
|
||||
if (currentWorker != null) currentWorker.dispose();
|
||||
|
||||
|
@ -884,12 +803,45 @@ public class VideoDetailFragment
|
|||
.subscribe((@NonNull StreamInfo result) -> {
|
||||
isLoading.set(false);
|
||||
currentInfo = result;
|
||||
showContentWithAnimation(120, 0, 0);
|
||||
handleResult(result);
|
||||
showContent();
|
||||
}, (@NonNull Throwable throwable) -> {
|
||||
isLoading.set(false);
|
||||
onError(throwable);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void initTabs() {
|
||||
pageAdapter.clearAllItems();
|
||||
|
||||
if(shouldShowComments()){
|
||||
pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG);
|
||||
}
|
||||
|
||||
if(showRelatedStreams && null == relatedStreamsLayout){
|
||||
//temp empty fragment. will be updated in handleResult
|
||||
pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG);
|
||||
}
|
||||
|
||||
pageAdapter.notifyDataSetUpdate();
|
||||
|
||||
if(pageAdapter.getCount() < 2){
|
||||
tabLayout.setVisibility(View.GONE);
|
||||
}else{
|
||||
tabLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldShowComments() {
|
||||
try {
|
||||
return showComments && NewPipe.getService(serviceId)
|
||||
.getServiceInfo()
|
||||
.getMediaCapabilities()
|
||||
.contains(COMMENTS);
|
||||
} catch (ExtractionException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1009,24 +961,6 @@ public class VideoDetailFragment
|
|||
}));
|
||||
}
|
||||
|
||||
private View getSeparatorView() {
|
||||
View separator = new View(activity);
|
||||
LinearLayout.LayoutParams params =
|
||||
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1);
|
||||
int m8 = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
|
||||
int m5 = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics());
|
||||
params.setMargins(m8, m5, m8, m5);
|
||||
separator.setLayoutParams(params);
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
activity.getTheme().resolveAttribute(R.attr.separator_color, typedValue, true);
|
||||
separator.setBackgroundColor(typedValue.data);
|
||||
|
||||
return separator;
|
||||
}
|
||||
|
||||
private void setHeightThumbnail() {
|
||||
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
|
||||
|
@ -1038,50 +972,8 @@ public class VideoDetailFragment
|
|||
thumbnailImageView.setMinimumHeight(height);
|
||||
}
|
||||
|
||||
private void showContentWithAnimation(long duration,
|
||||
long delay,
|
||||
@FloatRange(from = 0.0f, to = 1.0f)
|
||||
float translationPercent) {
|
||||
int translationY = (int) (getResources().getDisplayMetrics().heightPixels *
|
||||
(translationPercent > 0.0f ? translationPercent : .06f));
|
||||
|
||||
contentRootLayoutHiding.animate().setListener(null).cancel();
|
||||
contentRootLayoutHiding.setAlpha(0f);
|
||||
contentRootLayoutHiding.setTranslationY(translationY);
|
||||
contentRootLayoutHiding.setVisibility(View.VISIBLE);
|
||||
contentRootLayoutHiding.animate()
|
||||
.alpha(1f)
|
||||
.translationY(0)
|
||||
.setStartDelay(delay)
|
||||
.setDuration(duration)
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.start();
|
||||
|
||||
uploaderRootLayout.animate().setListener(null).cancel();
|
||||
uploaderRootLayout.setAlpha(0f);
|
||||
uploaderRootLayout.setTranslationY(translationY);
|
||||
uploaderRootLayout.setVisibility(View.VISIBLE);
|
||||
uploaderRootLayout.animate()
|
||||
.alpha(1f)
|
||||
.translationY(0)
|
||||
.setStartDelay((long) (duration * .5f) + delay)
|
||||
.setDuration(duration)
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.start();
|
||||
|
||||
if (showRelatedStreams) {
|
||||
relatedStreamRootLayout.animate().setListener(null).cancel();
|
||||
relatedStreamRootLayout.setAlpha(0f);
|
||||
relatedStreamRootLayout.setTranslationY(translationY);
|
||||
relatedStreamRootLayout.setVisibility(View.VISIBLE);
|
||||
relatedStreamRootLayout.animate()
|
||||
.alpha(1f)
|
||||
.translationY(0)
|
||||
.setStartDelay((long) (duration * .8f) + delay)
|
||||
.setDuration(duration)
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.start();
|
||||
}
|
||||
private void showContent() {
|
||||
AnimationUtils.slideUp(contentRootLayoutHiding,120, 96, 0.06f);
|
||||
}
|
||||
|
||||
protected void setInitialData(int serviceId, String url, String name) {
|
||||
|
@ -1116,7 +1008,7 @@ public class VideoDetailFragment
|
|||
public void showLoading() {
|
||||
super.showLoading();
|
||||
|
||||
animateView(contentRootLayoutHiding, false, 200);
|
||||
contentRootLayoutHiding.setVisibility(View.INVISIBLE);
|
||||
animateView(spinnerToolbar, false, 200);
|
||||
animateView(thumbnailPlayButton, false, 50);
|
||||
animateView(detailDurationView, false, 100);
|
||||
|
@ -1126,17 +1018,17 @@ public class VideoDetailFragment
|
|||
animateView(videoTitleTextView, true, 0);
|
||||
|
||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||
if (videoTitleToggleArrow != null) { //phone
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||
videoTitleToggleArrow.setVisibility(View.GONE);
|
||||
} else { //tablet
|
||||
final View related = (View) relatedStreamRootLayout.getParent();
|
||||
//don`t need to hide it if related streams are disabled
|
||||
if (related.getVisibility() == View.VISIBLE) {
|
||||
related.setVisibility(View.INVISIBLE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||
videoTitleToggleArrow.setVisibility(View.GONE);
|
||||
videoTitleRoot.setClickable(false);
|
||||
|
||||
if(relatedStreamsLayout != null){
|
||||
if(showRelatedStreams){
|
||||
relatedStreamsLayout.setVisibility(View.INVISIBLE);
|
||||
}else{
|
||||
relatedStreamsLayout.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
videoTitleRoot.setClickable(false);
|
||||
|
||||
imageLoader.cancelDisplayTask(thumbnailImageView);
|
||||
imageLoader.cancelDisplayTask(uploaderThumb);
|
||||
|
@ -1149,6 +1041,19 @@ public class VideoDetailFragment
|
|||
super.handleResult(info);
|
||||
|
||||
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName());
|
||||
|
||||
if(showRelatedStreams){
|
||||
if(null == relatedStreamsLayout){ //phone
|
||||
pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(currentInfo));
|
||||
pageAdapter.notifyDataSetUpdate();
|
||||
}else{ //tablet
|
||||
getChildFragmentManager().beginTransaction()
|
||||
.replace(R.id.relatedStreamsLayout, RelatedVideosFragment.getInstance(currentInfo))
|
||||
.commitNow();
|
||||
relatedStreamsLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
//pushToStack(serviceId, url, name);
|
||||
|
||||
animateView(thumbnailPlayButton, true, 200);
|
||||
|
@ -1213,14 +1118,10 @@ public class VideoDetailFragment
|
|||
}
|
||||
|
||||
videoDescriptionView.setVisibility(View.GONE);
|
||||
if (videoTitleToggleArrow != null) {
|
||||
videoTitleRoot.setClickable(true);
|
||||
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||
} else {
|
||||
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
videoTitleRoot.setClickable(true);
|
||||
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
||||
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
||||
videoDescriptionRootLayout.setVisibility(View.GONE);
|
||||
if (!TextUtils.isEmpty(info.getUploadDate())) {
|
||||
videoUploadDateView.setText(Localization.localizeDate(activity, info.getUploadDate()));
|
||||
}
|
||||
|
@ -1229,11 +1130,6 @@ public class VideoDetailFragment
|
|||
animateView(spinnerToolbar, true, 500);
|
||||
setupActionBar(info);
|
||||
initThumbnailViews(info);
|
||||
initRelatedVideos(info);
|
||||
if (wasRelatedStreamsExpanded) {
|
||||
toggleExpandRelatedVideos(currentInfo);
|
||||
wasRelatedStreamsExpanded = false;
|
||||
}
|
||||
|
||||
setTitleToUrl(info.getServiceId(), info.getUrl(), info.getName());
|
||||
setTitleToUrl(info.getServiceId(), info.getOriginalUrl(), info.getName());
|
||||
|
@ -1268,11 +1164,6 @@ public class VideoDetailFragment
|
|||
// Only auto play in the first open
|
||||
autoPlayEnabled = false;
|
||||
}
|
||||
|
||||
final ViewParent related = relatedStreamRootLayout.getParent();
|
||||
if (related instanceof ScrollView) {
|
||||
((ScrollView) related).scrollTo(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1339,13 +1230,4 @@ public class VideoDetailFragment
|
|||
|
||||
showError(getString(R.string.blocked_by_gema), false, R.drawable.gruese_die_gema);
|
||||
}
|
||||
|
||||
private void setRelatedStreamsVisibility(int visibility) {
|
||||
final ViewParent parent = relatedStreamRootLayout.getParent();
|
||||
if (parent instanceof ScrollView) {
|
||||
((ScrollView) parent).setVisibility(visibility);
|
||||
} else {
|
||||
relatedStreamRootLayout.setVisibility(visibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.view.View;
|
|||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||
|
@ -220,6 +221,13 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
|
|||
}
|
||||
});
|
||||
|
||||
infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture<CommentsInfoItem>() {
|
||||
@Override
|
||||
public void selected(CommentsInfoItem selectedItem) {
|
||||
onItemSelected(selectedItem);
|
||||
}
|
||||
});
|
||||
|
||||
itemsList.clearOnScrollListeners();
|
||||
itemsList.addOnScrollListener(new OnScrollBelowItemsListener() {
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
package org.schabi.newpipe.fragments.list.comments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfo;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
|
||||
|
||||
private CompositeDisposable disposables = new CompositeDisposable();
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Views
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
|
||||
|
||||
private boolean mIsVisibleToUser = false;
|
||||
|
||||
public static CommentsFragment getInstance(int serviceId, String url, String name) {
|
||||
CommentsFragment instance = new CommentsFragment();
|
||||
instance.setInitialData(serviceId, url, name);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// LifeCycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
mIsVisibleToUser = isVisibleToUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_comments, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (disposables != null) disposables.clear();
|
||||
}
|
||||
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Load and handle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
|
||||
return ExtractorHelper.getMoreCommentItems(serviceId, currentInfo, currentNextPageUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Single<CommentsInfo> loadResult(boolean forceLoad) {
|
||||
return ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Contract
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void showLoading() {
|
||||
super.showLoading();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(@NonNull CommentsInfo result) {
|
||||
super.handleResult(result);
|
||||
|
||||
AnimationUtils.slideUp(getView(),120, 96, 0.06f);
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
|
||||
}
|
||||
|
||||
if (disposables != null) disposables.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleNextItems(ListExtractor.InfoItemsPage result) {
|
||||
super.handleNextItems(result);
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(),
|
||||
UserAction.REQUESTED_COMMENTS,
|
||||
NewPipe.getNameOfService(serviceId),
|
||||
"Get next page of: " + url,
|
||||
R.string.general_error);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// OnError
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected boolean onError(Throwable exception) {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
hideLoading();
|
||||
showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isGridLayout() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
package org.schabi.newpipe.fragments.list.videos;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.Switch;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||
import org.schabi.newpipe.report.UserAction;
|
||||
import org.schabi.newpipe.util.AnimationUtils;
|
||||
import org.schabi.newpipe.util.RelatedStreamInfo;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
|
||||
public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInfo> implements SharedPreferences.OnSharedPreferenceChangeListener{
|
||||
|
||||
private CompositeDisposable disposables = new CompositeDisposable();
|
||||
private RelatedStreamInfo relatedStreamInfo;
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Views
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
private View headerRootLayout;
|
||||
private Switch aSwitch;
|
||||
|
||||
private boolean mIsVisibleToUser = false;
|
||||
|
||||
public static RelatedVideosFragment getInstance(StreamInfo info) {
|
||||
RelatedVideosFragment instance = new RelatedVideosFragment();
|
||||
instance.setInitialData(info);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// LifeCycle
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void setUserVisibleHint(boolean isVisibleToUser) {
|
||||
super.setUserVisibleHint(isVisibleToUser);
|
||||
mIsVisibleToUser = isVisibleToUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_related_streams, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (disposables != null) disposables.clear();
|
||||
}
|
||||
|
||||
protected View getListHeader(){
|
||||
if(relatedStreamInfo != null && relatedStreamInfo.getNextStream() != null){
|
||||
headerRootLayout = activity.getLayoutInflater().inflate(R.layout.related_streams_header, itemsList, false);
|
||||
aSwitch = headerRootLayout.findViewById(R.id.autoplay_switch);
|
||||
|
||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
Boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
|
||||
aSwitch.setChecked(autoplay);
|
||||
aSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
|
||||
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
|
||||
prefEdit.putBoolean(getString(R.string.auto_queue_key), b);
|
||||
prefEdit.apply();
|
||||
}
|
||||
});
|
||||
return headerRootLayout;
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Single<ListExtractor.InfoItemsPage> loadMoreItemsLogic() {
|
||||
return Single.fromCallable(() -> ListExtractor.InfoItemsPage.emptyPage());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Single<RelatedStreamInfo> loadResult(boolean forceLoad) {
|
||||
return Single.fromCallable(() -> relatedStreamInfo);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Contract
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void showLoading() {
|
||||
super.showLoading();
|
||||
if(null != headerRootLayout) headerRootLayout.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleResult(@NonNull RelatedStreamInfo result) {
|
||||
|
||||
super.handleResult(result);
|
||||
|
||||
if(null != headerRootLayout) headerRootLayout.setVisibility(View.VISIBLE);
|
||||
AnimationUtils.slideUp(getView(),120, 96, 0.06f);
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(), UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
|
||||
}
|
||||
|
||||
if (disposables != null) disposables.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleNextItems(ListExtractor.InfoItemsPage result) {
|
||||
super.handleNextItems(result);
|
||||
|
||||
if (!result.getErrors().isEmpty()) {
|
||||
showSnackBarError(result.getErrors(),
|
||||
UserAction.REQUESTED_STREAM,
|
||||
NewPipe.getNameOfService(serviceId),
|
||||
"Get next page of: " + url,
|
||||
R.string.general_error);
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// OnError
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
protected boolean onError(Throwable exception) {
|
||||
if (super.onError(exception)) return true;
|
||||
|
||||
hideLoading();
|
||||
showSnackBarError(exception, UserAction.REQUESTED_STREAM, NewPipe.getNameOfService(serviceId), url, R.string.general_error);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void setTitle(String title) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void setInitialData(StreamInfo info) {
|
||||
super.setInitialData(info.getServiceId(), info.getUrl(), info.getName());
|
||||
if(this.relatedStreamInfo == null) this.relatedStreamInfo = RelatedStreamInfo.getInfo(info);
|
||||
}
|
||||
|
||||
|
||||
private static final String INFO_KEY = "related_info_key";
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putSerializable(INFO_KEY, relatedStreamInfo);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(@NonNull Bundle savedState) {
|
||||
super.onRestoreInstanceState(savedState);
|
||||
if (savedState != null) {
|
||||
Serializable serializable = savedState.getSerializable(INFO_KEY);
|
||||
if(serializable instanceof RelatedStreamInfo){
|
||||
this.relatedStreamInfo = (RelatedStreamInfo) serializable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
|
||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
Boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
|
||||
if(null != aSwitch) aSwitch.setChecked(autoplay);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isGridLayout() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -10,10 +10,13 @@ import com.nostra13.universalimageloader.core.ImageLoader;
|
|||
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
||||
|
@ -50,6 +53,7 @@ public class InfoItemBuilder {
|
|||
private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
|
||||
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
|
||||
private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener;
|
||||
private OnClickGesture<CommentsInfoItem> onCommentsSelectedListener;
|
||||
|
||||
public InfoItemBuilder(Context context) {
|
||||
this.context = context;
|
||||
|
@ -73,6 +77,8 @@ public class InfoItemBuilder {
|
|||
return useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) : new ChannelInfoItemHolder(this, parent);
|
||||
case PLAYLIST:
|
||||
return useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) : new PlaylistInfoItemHolder(this, parent);
|
||||
case COMMENT:
|
||||
return useMiniVariant ? new CommentsMiniInfoItemHolder(this, parent) : new CommentsInfoItemHolder(this, parent);
|
||||
default:
|
||||
Log.e(TAG, "Trollolo");
|
||||
throw new RuntimeException("InfoType not expected = " + infoType.name());
|
||||
|
@ -111,4 +117,12 @@ public class InfoItemBuilder {
|
|||
this.onPlaylistSelectedListener = listener;
|
||||
}
|
||||
|
||||
public OnClickGesture<CommentsInfoItem> getOnCommentsSelectedListener() {
|
||||
return onCommentsSelectedListener;
|
||||
}
|
||||
|
||||
public void setOnCommentsSelectedListener(OnClickGesture<CommentsInfoItem> onCommentsSelectedListener) {
|
||||
this.onCommentsSelectedListener = onCommentsSelectedListener;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,10 +9,13 @@ import android.view.ViewGroup;
|
|||
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
||||
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
|
||||
|
@ -63,6 +66,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||
private static final int MINI_PLAYLIST_HOLDER_TYPE = 0x300;
|
||||
private static final int PLAYLIST_HOLDER_TYPE = 0x301;
|
||||
private static final int GRID_PLAYLIST_HOLDER_TYPE = 0x302;
|
||||
private static final int MINI_COMMENT_HOLDER_TYPE = 0x400;
|
||||
private static final int COMMENT_HOLDER_TYPE = 0x401;
|
||||
|
||||
private final InfoItemBuilder infoItemBuilder;
|
||||
private final ArrayList<InfoItem> infoItemList;
|
||||
|
@ -98,6 +103,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||
infoItemBuilder.setOnPlaylistSelectedListener(listener);
|
||||
}
|
||||
|
||||
public void setOnCommentsSelectedListener(OnClickGesture<CommentsInfoItem> listener) {
|
||||
infoItemBuilder.setOnCommentsSelectedListener(listener);
|
||||
}
|
||||
|
||||
public void useMiniItemVariants(boolean useMiniVariant) {
|
||||
this.useMiniVariant = useMiniVariant;
|
||||
}
|
||||
|
@ -223,6 +232,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||
return useGridVariant ? GRID_CHANNEL_HOLDER_TYPE : useMiniVariant ? MINI_CHANNEL_HOLDER_TYPE : CHANNEL_HOLDER_TYPE;
|
||||
case PLAYLIST:
|
||||
return useGridVariant ? GRID_PLAYLIST_HOLDER_TYPE : useMiniVariant ? MINI_PLAYLIST_HOLDER_TYPE : PLAYLIST_HOLDER_TYPE;
|
||||
case COMMENT:
|
||||
return useMiniVariant ? MINI_COMMENT_HOLDER_TYPE : COMMENT_HOLDER_TYPE;
|
||||
default:
|
||||
Log.e(TAG, "Trollolo");
|
||||
return -1;
|
||||
|
@ -231,7 +242,8 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
|
||||
if (DEBUG) Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], type = [" + type + "]");
|
||||
if (DEBUG)
|
||||
Log.d(TAG, "onCreateViewHolder() called with: parent = [" + parent + "], type = [" + type + "]");
|
||||
switch (type) {
|
||||
case HEADER_TYPE:
|
||||
return new HFHolder(header);
|
||||
|
@ -255,6 +267,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||
return new PlaylistInfoItemHolder(infoItemBuilder, parent);
|
||||
case GRID_PLAYLIST_HOLDER_TYPE:
|
||||
return new PlaylistGridInfoItemHolder(infoItemBuilder, parent);
|
||||
case MINI_COMMENT_HOLDER_TYPE:
|
||||
return new CommentsMiniInfoItemHolder(infoItemBuilder, parent);
|
||||
case COMMENT_HOLDER_TYPE:
|
||||
return new CommentsInfoItemHolder(infoItemBuilder, parent);
|
||||
default:
|
||||
Log.e(TAG, "Trollolo");
|
||||
return new FallbackViewHolder(new View(parent.getContext()));
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package org.schabi.newpipe.info_list.holder;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.util.Localization;
|
||||
|
||||
/*
|
||||
* Created by Christian Schabesberger on 12.02.17.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* ChannelInfoItemHolder .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 CommentsInfoItemHolder extends CommentsMiniInfoItemHolder {
|
||||
|
||||
public final TextView itemTitleView;
|
||||
|
||||
public CommentsInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||
super(infoItemBuilder, R.layout.list_comments_item, parent);
|
||||
|
||||
itemTitleView = itemView.findViewById(R.id.itemTitleView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFromItem(final InfoItem infoItem) {
|
||||
super.updateFromItem(infoItem);
|
||||
|
||||
if (!(infoItem instanceof CommentsInfoItem)) return;
|
||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
||||
|
||||
itemTitleView.setText(item.getAuthorName());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package org.schabi.newpipe.info_list.holder;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||
public final CircleImageView itemThumbnailView;
|
||||
private final TextView itemContentView;
|
||||
private final TextView itemLikesCountView;
|
||||
private final TextView itemDislikesCountView;
|
||||
private final TextView itemPublishedTime;
|
||||
|
||||
private static final int commentDefaultLines = 2;
|
||||
private static final int commentExpandedLines = 1000;
|
||||
|
||||
CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, int layoutId, ViewGroup parent) {
|
||||
super(infoItemBuilder, layoutId, parent);
|
||||
|
||||
itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView);
|
||||
itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view);
|
||||
itemDislikesCountView = itemView.findViewById(R.id.detail_thumbs_down_count_view);
|
||||
itemPublishedTime = itemView.findViewById(R.id.itemPublishedTime);
|
||||
itemContentView = itemView.findViewById(R.id.itemCommentContentView);
|
||||
}
|
||||
|
||||
public CommentsMiniInfoItemHolder(InfoItemBuilder infoItemBuilder, ViewGroup parent) {
|
||||
this(infoItemBuilder, R.layout.list_comments_mini_item, parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFromItem(final InfoItem infoItem) {
|
||||
if (!(infoItem instanceof CommentsInfoItem)) return;
|
||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
||||
|
||||
itemBuilder.getImageLoader()
|
||||
.displayImage(item.getAuthorThumbnail(),
|
||||
itemThumbnailView,
|
||||
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS);
|
||||
|
||||
itemThumbnailView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
try {
|
||||
final AppCompatActivity activity = (AppCompatActivity) itemBuilder.getContext();
|
||||
NavigationHelper.openChannelFragment(
|
||||
activity.getSupportFragmentManager(),
|
||||
item.getServiceId(),
|
||||
item.getAuthorEndpoint(),
|
||||
item.getAuthorName());
|
||||
} catch (Exception e) {
|
||||
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// ellipsize if not already ellipsized
|
||||
if (null == itemContentView.getEllipsize()) {
|
||||
itemContentView.setEllipsize(TextUtils.TruncateAt.END);
|
||||
itemContentView.setMaxLines(commentDefaultLines);
|
||||
}
|
||||
|
||||
itemContentView.setText(item.getCommentText());
|
||||
if (null != item.getLikeCount()) {
|
||||
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
|
||||
}
|
||||
itemPublishedTime.setText(item.getPublishedTime());
|
||||
|
||||
itemView.setOnClickListener(view -> {
|
||||
toggleEllipsize(item.getCommentText());
|
||||
if (itemBuilder.getOnCommentsSelectedListener() != null) {
|
||||
itemBuilder.getOnCommentsSelectedListener().selected(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void toggleEllipsize(String text) {
|
||||
// toggle ellipsize
|
||||
if (null == itemContentView.getEllipsize()) {
|
||||
itemContentView.setEllipsize(TextUtils.TruncateAt.END);
|
||||
itemContentView.setMaxLines(commentDefaultLines);
|
||||
} else {
|
||||
itemContentView.setEllipsize(null);
|
||||
itemContentView.setMaxLines(commentExpandedLines);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,7 +45,9 @@ import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MOD
|
|||
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIT;
|
||||
import static com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.*;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_BACKGROUND;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_NONE;
|
||||
import static org.schabi.newpipe.player.helper.PlayerHelper.MinimizeMode.MINIMIZE_ON_EXIT_MODE_POPUP;
|
||||
|
||||
public class PlayerHelper {
|
||||
private PlayerHelper() {}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.MediaFormat;
|
|||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.player.helper.PlayerDataSource;
|
||||
import org.schabi.newpipe.player.helper.PlayerHelper;
|
||||
|
|
|
@ -15,6 +15,7 @@ public enum UserAction {
|
|||
REQUESTED_CHANNEL("requested channel"),
|
||||
REQUESTED_PLAYLIST("requested playlist"),
|
||||
REQUESTED_KIOSK("requested kiosk"),
|
||||
REQUESTED_COMMENTS("requested comments"),
|
||||
DELETE_FROM_HISTORY("delete from history"),
|
||||
PLAY_STREAM("Play stream");
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.animation.ArgbEvaluator;
|
|||
import android.animation.ValueAnimator;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.FloatRange;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.util.Log;
|
||||
|
@ -363,4 +364,24 @@ public class AnimationUtils {
|
|||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void slideUp(final View view,
|
||||
long duration,
|
||||
long delay,
|
||||
@FloatRange(from = 0.0f, to = 1.0f) float translationPercent) {
|
||||
int translationY = (int) (view.getResources().getDisplayMetrics().heightPixels *
|
||||
(translationPercent));
|
||||
|
||||
view.animate().setListener(null).cancel();
|
||||
view.setAlpha(0f);
|
||||
view.setTranslationY(translationY);
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.animate()
|
||||
.alpha(1f)
|
||||
.translationY(0)
|
||||
.setStartDelay(delay)
|
||||
.setDuration(duration)
|
||||
.setInterpolator(new FastOutSlowInInterpolator())
|
||||
.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,11 +29,12 @@ import org.schabi.newpipe.MainActivity;
|
|||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.ReCaptchaActivity;
|
||||
import org.schabi.newpipe.extractor.Info;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.ListExtractor.InfoItemsPage;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.SuggestionExtractor;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.comments.CommentsInfo;
|
||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||
|
@ -62,7 +63,7 @@ public final class ExtractorHelper {
|
|||
}
|
||||
|
||||
private static void checkServiceId(int serviceId) {
|
||||
if(serviceId == Constants.NO_SERVICE_ID) {
|
||||
if (serviceId == Constants.NO_SERVICE_ID) {
|
||||
throw new IllegalArgumentException("serviceId is NO_SERVICE_ID");
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ public final class ExtractorHelper {
|
|||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.STREAM, Single.fromCallable(() ->
|
||||
StreamInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
|
@ -118,29 +119,45 @@ public final class ExtractorHelper {
|
|||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.CHANNEL, Single.fromCallable(() ->
|
||||
ChannelInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
public static Single<InfoItemsPage> getMoreChannelItems(final int serviceId,
|
||||
final String url,
|
||||
final String nextStreamsUrl) {
|
||||
final String url,
|
||||
final String nextStreamsUrl) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(() ->
|
||||
ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
|
||||
}
|
||||
|
||||
public static Single<CommentsInfo> getCommentsInfo(final int serviceId,
|
||||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.COMMENT, Single.fromCallable(() ->
|
||||
CommentsInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
public static Single<InfoItemsPage> getMoreCommentItems(final int serviceId,
|
||||
final CommentsInfo info,
|
||||
final String nextPageUrl) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(() ->
|
||||
CommentsInfo.getMoreItems(NewPipe.getService(serviceId), info, nextPageUrl));
|
||||
}
|
||||
|
||||
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId,
|
||||
final String url,
|
||||
boolean forceLoad) {
|
||||
checkServiceId(serviceId);
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.PLAYLIST, Single.fromCallable(() ->
|
||||
PlaylistInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
public static Single<InfoItemsPage> getMorePlaylistItems(final int serviceId,
|
||||
final String url,
|
||||
final String nextStreamsUrl) {
|
||||
final String url,
|
||||
final String nextStreamsUrl) {
|
||||
checkServiceId(serviceId);
|
||||
return Single.fromCallable(() ->
|
||||
PlaylistInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl));
|
||||
|
@ -149,7 +166,7 @@ public final class ExtractorHelper {
|
|||
public static Single<KioskInfo> getKioskInfo(final int serviceId,
|
||||
final String url,
|
||||
boolean forceLoad) {
|
||||
return checkCache(forceLoad, serviceId, url, Single.fromCallable(() ->
|
||||
return checkCache(forceLoad, serviceId, url, InfoItem.InfoType.PLAYLIST, Single.fromCallable(() ->
|
||||
KioskInfo.getInfo(NewPipe.getService(serviceId), url)));
|
||||
}
|
||||
|
||||
|
@ -173,16 +190,17 @@ public final class ExtractorHelper {
|
|||
private static <I extends Info> Single<I> checkCache(boolean forceLoad,
|
||||
int serviceId,
|
||||
String url,
|
||||
InfoItem.InfoType infoType,
|
||||
Single<I> loadFromNetwork) {
|
||||
checkServiceId(serviceId);
|
||||
loadFromNetwork = loadFromNetwork.doOnSuccess(info -> cache.putInfo(serviceId, url, info));
|
||||
loadFromNetwork = loadFromNetwork.doOnSuccess(info -> cache.putInfo(serviceId, url, info, infoType));
|
||||
|
||||
Single<I> load;
|
||||
if (forceLoad) {
|
||||
cache.removeInfo(serviceId, url);
|
||||
cache.removeInfo(serviceId, url, infoType);
|
||||
load = loadFromNetwork;
|
||||
} else {
|
||||
load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url),
|
||||
load = Maybe.concat(ExtractorHelper.loadFromCache(serviceId, url, infoType),
|
||||
loadFromNetwork.toMaybe())
|
||||
.firstElement() //Take the first valid
|
||||
.toSingle();
|
||||
|
@ -194,20 +212,20 @@ public final class ExtractorHelper {
|
|||
/**
|
||||
* Default implementation uses the {@link InfoCache} to get cached results
|
||||
*/
|
||||
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url) {
|
||||
public static <I extends Info> Maybe<I> loadFromCache(final int serviceId, final String url, InfoItem.InfoType infoType) {
|
||||
checkServiceId(serviceId);
|
||||
return Maybe.defer(() -> {
|
||||
//noinspection unchecked
|
||||
I info = (I) cache.getFromKey(serviceId, url);
|
||||
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
|
||||
//noinspection unchecked
|
||||
I info = (I) cache.getFromKey(serviceId, url, infoType);
|
||||
if (MainActivity.DEBUG) Log.d(TAG, "loadFromCache() called, info > " + info);
|
||||
|
||||
// Only return info if it's not null (it is cached)
|
||||
if (info != null) {
|
||||
return Maybe.just(info);
|
||||
}
|
||||
// Only return info if it's not null (it is cached)
|
||||
if (info != null) {
|
||||
return Maybe.just(info);
|
||||
}
|
||||
|
||||
return Maybe.empty();
|
||||
});
|
||||
return Maybe.empty();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.util.Log;
|
|||
|
||||
import org.schabi.newpipe.MainActivity;
|
||||
import org.schabi.newpipe.extractor.Info;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -52,27 +53,27 @@ public final class InfoCache {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
public Info getFromKey(int serviceId, @NonNull String url) {
|
||||
public Info getFromKey(int serviceId, @NonNull String url, @NonNull InfoItem.InfoType infoType) {
|
||||
if (DEBUG) Log.d(TAG, "getFromKey() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
|
||||
synchronized (lruCache) {
|
||||
return getInfo(keyOf(serviceId, url));
|
||||
return getInfo(keyOf(serviceId, url, infoType));
|
||||
}
|
||||
}
|
||||
|
||||
public void putInfo(int serviceId, @NonNull String url, @NonNull Info info) {
|
||||
public void putInfo(int serviceId, @NonNull String url, @NonNull Info info, @NonNull InfoItem.InfoType infoType) {
|
||||
if (DEBUG) Log.d(TAG, "putInfo() called with: info = [" + info + "]");
|
||||
|
||||
final long expirationMillis = ServiceHelper.getCacheExpirationMillis(info.getServiceId());
|
||||
synchronized (lruCache) {
|
||||
final CacheData data = new CacheData(info, expirationMillis);
|
||||
lruCache.put(keyOf(serviceId, url), data);
|
||||
lruCache.put(keyOf(serviceId, url, infoType), data);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeInfo(int serviceId, @NonNull String url) {
|
||||
public void removeInfo(int serviceId, @NonNull String url, @NonNull InfoItem.InfoType infoType) {
|
||||
if (DEBUG) Log.d(TAG, "removeInfo() called with: serviceId = [" + serviceId + "], url = [" + url + "]");
|
||||
synchronized (lruCache) {
|
||||
lruCache.remove(keyOf(serviceId, url));
|
||||
lruCache.remove(keyOf(serviceId, url, infoType));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,8 +99,8 @@ public final class InfoCache {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
private static String keyOf(final int serviceId, @NonNull final String url) {
|
||||
return serviceId + url;
|
||||
private static String keyOf(final int serviceId, @NonNull final String url, @NonNull InfoItem.InfoType infoType) {
|
||||
return serviceId + url + infoType.toString();
|
||||
}
|
||||
|
||||
private static void removeStaleCache() {
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.schabi.newpipe.extractor.stream.VideoStream;
|
|||
import org.schabi.newpipe.fragments.MainFragment;
|
||||
import org.schabi.newpipe.fragments.detail.VideoDetailFragment;
|
||||
import org.schabi.newpipe.fragments.list.channel.ChannelFragment;
|
||||
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
|
||||
import org.schabi.newpipe.local.bookmark.BookmarkFragment;
|
||||
import org.schabi.newpipe.local.feed.FeedFragment;
|
||||
import org.schabi.newpipe.fragments.list.kiosk.KioskFragment;
|
||||
|
@ -309,6 +310,18 @@ public class NavigationHelper {
|
|||
.commit();
|
||||
}
|
||||
|
||||
public static void openCommentsFragment(
|
||||
FragmentManager fragmentManager,
|
||||
int serviceId,
|
||||
String url,
|
||||
String name) {
|
||||
if (name == null) name = "";
|
||||
fragmentManager.beginTransaction().setCustomAnimations(R.anim.switch_service_in, R.anim.switch_service_out)
|
||||
.replace(R.id.fragment_holder, CommentsFragment.getInstance(serviceId, url, name))
|
||||
.addToBackStack(null)
|
||||
.commit();
|
||||
}
|
||||
|
||||
public static void openPlaylistFragment(FragmentManager fragmentManager,
|
||||
int serviceId,
|
||||
String url,
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package org.schabi.newpipe.util;
|
||||
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.ListInfo;
|
||||
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class RelatedStreamInfo extends ListInfo<InfoItem> {
|
||||
|
||||
private StreamInfoItem nextStream;
|
||||
|
||||
public RelatedStreamInfo(int serviceId, ListLinkHandler listUrlIdHandler, String name) {
|
||||
super(serviceId, listUrlIdHandler, name);
|
||||
}
|
||||
|
||||
public static RelatedStreamInfo getInfo(StreamInfo info) {
|
||||
ListLinkHandler handler = new ListLinkHandler(info.getOriginalUrl(), info.getUrl(), info.getId(), Collections.emptyList(), null);
|
||||
RelatedStreamInfo relatedStreamInfo = new RelatedStreamInfo(info.getServiceId(), handler, info.getName());
|
||||
List<InfoItem> streams = new ArrayList<>();
|
||||
if(info.getNextVideo() != null){
|
||||
streams.add(info.getNextVideo());
|
||||
}
|
||||
streams.addAll(info.getRelatedStreams());
|
||||
relatedStreamInfo.setRelatedItems(streams);
|
||||
relatedStreamInfo.setNextStream(info.getNextVideo());
|
||||
return relatedStreamInfo;
|
||||
}
|
||||
|
||||
public StreamInfoItem getNextStream() {
|
||||
return nextStream;
|
||||
}
|
||||
|
||||
public void setNextStream(StreamInfoItem nextStream) {
|
||||
this.nextStream = nextStream;
|
||||
}
|
||||
}
|
12
app/src/main/res/drawable/default_dot.xml
Normal file
12
app/src/main/res/drawable/default_dot.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:innerRadius="0dp"
|
||||
android:shape="ring"
|
||||
android:thickness="4dp"
|
||||
android:useLevel="false">
|
||||
<solid android:color="@android:color/darker_gray"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
12
app/src/main/res/drawable/selected_dot.xml
Normal file
12
app/src/main/res/drawable/selected_dot.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape
|
||||
android:innerRadius="0dp"
|
||||
android:shape="ring"
|
||||
android:thickness="6dp"
|
||||
android:useLevel="false">
|
||||
<solid android:color="@android:color/darker_gray"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
8
app/src/main/res/drawable/tab_selector.xml
Normal file
8
app/src/main/res/drawable/tab_selector.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:drawable="@drawable/selected_dot"
|
||||
android:state_selected="true"/>
|
||||
|
||||
<item android:drawable="@drawable/default_dot"/>
|
||||
</selector>
|
|
@ -8,107 +8,121 @@
|
|||
android:focusableInTouchMode="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.nirhart.parallaxscroll.views.ParallaxScrollView
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/detail_main_content"
|
||||
app:parallax_factor="1.9"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="5">
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="5"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<!--WRAPPER-->
|
||||
<LinearLayout
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appbarlayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:fitsSystemWindows="true"
|
||||
app:elevation="0dp"
|
||||
app:layout_behavior="android.support.design.widget.FlingBehavior">
|
||||
|
||||
<!-- THUMBNAIL -->
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_thumbnail_root_layout"
|
||||
<android.support.design.widget.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/black"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
app:layout_scrollFlags="scroll">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_image_view"
|
||||
<!-- THUMBNAIL -->
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_thumbnail_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/detail_thumbnail_view_description"
|
||||
android:scaleType="fitCenter"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:layout_height="200dp"
|
||||
tools:src="@drawable/dummy_thumbnail" />
|
||||
android:background="@android:color/black"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:layout_collapseMode="parallax">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_play_button"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:src="@drawable/new_play_arrow"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/detail_thumbnail_view_description"
|
||||
android:scaleType="fitCenter"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:layout_height="200dp"
|
||||
tools:src="@drawable/dummy_thumbnail" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/touch_append_detail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="#64000000"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingTop="10dp"
|
||||
android:text="@string/hold_to_append"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible" />
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_play_button"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:src="@drawable/new_play_arrow"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_duration_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:alpha=".6"
|
||||
android:background="#23000000"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12:38"
|
||||
tools:visibility="visible" />
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:id="@+id/touch_append_detail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="#64000000"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingTop="10dp"
|
||||
android:text="@string/hold_to_append"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_duration_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:alpha=".6"
|
||||
android:background="#23000000"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12:38"
|
||||
tools:visibility="visible" />
|
||||
</FrameLayout>
|
||||
|
||||
</android.support.design.widget.CollapsingToolbarLayout>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/detail_content_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:windowBackground">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:windowBackground"
|
||||
app:layout_scrollFlags="scroll">
|
||||
|
||||
<!-- TITLE -->
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_title_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingRight="12dp">
|
||||
|
||||
|
@ -126,6 +140,15 @@
|
|||
tools:ignore="RtlHardcoded"
|
||||
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero." />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_toggle_description_view"
|
||||
android:layout_width="15dp"
|
||||
android:layout_height="15dp"
|
||||
android:layout_gravity="center_vertical|right"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:src="@drawable/arrow_down"
|
||||
tools:ignore="ContentDescription,RtlHardcoded" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<!-- LOADING INDICATOR-->
|
||||
|
@ -209,17 +232,17 @@
|
|||
tools:text="Uploader" />
|
||||
|
||||
<!--<Button
|
||||
android:id="@+id/detail_uploader_subscribe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|right"
|
||||
android:layout_marginRight="12dp"
|
||||
android:text="@string/rss_button_title"
|
||||
android:textSize="12sp"
|
||||
android:theme="@style/RedButton"
|
||||
android:drawableLeft="@drawable/ic_rss_feed_white_24dp"
|
||||
tools:ignore="RtlHardcoded"
|
||||
android:visibility="gone"/>-->
|
||||
android:id="@+id/detail_uploader_subscribe"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|right"
|
||||
android:layout_marginRight="12dp"
|
||||
android:text="@string/rss_button_title"
|
||||
android:textSize="12sp"
|
||||
android:theme="@style/RedButton"
|
||||
android:drawableLeft="@drawable/ic_rss_feed_white_24dp"
|
||||
tools:ignore="RtlHardcoded"
|
||||
android:visibility="gone"/>-->
|
||||
</LinearLayout>
|
||||
|
||||
<!-- VIEW & THUMBS -->
|
||||
|
@ -401,7 +424,9 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_upload_date_view"
|
||||
|
@ -435,57 +460,39 @@
|
|||
android:background="?attr/separator_color" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</com.nirhart.parallaxscroll.views.ParallaxScrollView>
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center"
|
||||
android:background="@color/transparent_background_color"
|
||||
app:tabBackground="@drawable/tab_selector"
|
||||
app:tabGravity="center"
|
||||
app:tabIndicatorHeight="0dp">
|
||||
|
||||
</android.support.design.widget.TabLayout>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/relatedStreamsLayout"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="3">
|
||||
|
||||
<!--NEXT AND RELATED VIDEOS-->
|
||||
<LinearLayout
|
||||
android:id="@+id/detail_related_streams_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingTop="14dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_next_stream_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:text="@string/next_video_title"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_next_text_size"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/detail_related_streams_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="2dp"
|
||||
android:orientation="vertical"
|
||||
tools:minHeight="50dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/detail_related_streams_expand"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingTop="4dp"
|
||||
android:src="?attr/expand"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="true"
|
||||
tools:ignore="ContentDescription" />
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
|
71
app/src/main/res/layout/fragment_comments.xml
Normal file
71
app/src/main/res/layout/fragment_comments.xml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/items_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
tools:listitem="@layout/list_comments_item"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/empty_state_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="90dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:fontFamily="monospace"
|
||||
android:text="(╯°-°)╯"
|
||||
android:textSize="35sp"
|
||||
tools:ignore="HardcodedText,UnusedAttribute"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/empty_view_no_comments"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!--ERROR PANEL-->
|
||||
<include
|
||||
android:id="@+id/error_panel"
|
||||
layout="@layout/error_retry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="50dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:background="?attr/toolbar_shadow_drawable"
|
||||
android:layout_alignParentTop="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</RelativeLayout>
|
71
app/src/main/res/layout/fragment_related_streams.xml
Normal file
71
app/src/main/res/layout/fragment_related_streams.xml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/items_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
tools:listitem="@layout/list_stream_item"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading_progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/empty_state_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="90dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:fontFamily="monospace"
|
||||
android:text="(╯°-°)╯"
|
||||
android:textSize="35sp"
|
||||
tools:ignore="HardcodedText,UnusedAttribute"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/empty_view_no_videos"
|
||||
android:textSize="24sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!--ERROR PANEL-->
|
||||
<include
|
||||
android:id="@+id/error_panel"
|
||||
layout="@layout/error_retry"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_marginTop="50dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:background="?attr/toolbar_shadow_drawable"
|
||||
android:layout_alignParentTop="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</RelativeLayout>
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/video_item_detail"
|
||||
|
@ -8,101 +7,111 @@
|
|||
android:layout_height="match_parent"
|
||||
android:focusableInTouchMode="true">
|
||||
|
||||
<com.nirhart.parallaxscroll.views.ParallaxScrollView
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/detail_main_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="visible"
|
||||
app:parallax_factor="1.9">
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<!--WRAPPER-->
|
||||
<LinearLayout
|
||||
<android.support.design.widget.AppBarLayout
|
||||
android:id="@+id/appbarlayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:fitsSystemWindows="true"
|
||||
app:elevation="0dp"
|
||||
app:layout_behavior="android.support.design.widget.FlingBehavior">
|
||||
|
||||
<!-- THUMBNAIL -->
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_thumbnail_root_layout"
|
||||
<android.support.design.widget.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/black"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
app:layout_scrollFlags="scroll">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_image_view"
|
||||
<!-- THUMBNAIL -->
|
||||
<FrameLayout
|
||||
android:id="@+id/detail_thumbnail_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/detail_thumbnail_view_description"
|
||||
android:scaleType="fitCenter"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:layout_height="200dp"
|
||||
tools:src="@drawable/dummy_thumbnail"/>
|
||||
android:background="@android:color/black"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
app:layout_collapseMode="parallax">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_play_button"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:src="@drawable/new_play_arrow"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible"/>
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_image_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@android:color/transparent"
|
||||
android:contentDescription="@string/detail_thumbnail_view_description"
|
||||
android:scaleType="fitCenter"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:layout_height="200dp"
|
||||
tools:src="@drawable/dummy_thumbnail" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/touch_append_detail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#64000000"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingTop="10dp"
|
||||
android:layout_gravity="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/hold_to_append"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible"/>
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbnail_play_button"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
android:layout_gravity="center"
|
||||
android:background="@android:color/transparent"
|
||||
android:src="@drawable/new_play_arrow"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_duration_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:alpha=".6"
|
||||
android:background="#23000000"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12:38"
|
||||
tools:visibility="visible"/>
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:id="@+id/touch_append_detail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="#64000000"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingLeft="30dp"
|
||||
android:paddingRight="30dp"
|
||||
android:paddingTop="10dp"
|
||||
android:text="@string/hold_to_append"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_duration_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|right"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:alpha=".6"
|
||||
android:background="#23000000"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp"
|
||||
android:paddingTop="2dp"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12:38"
|
||||
tools:visibility="visible" />
|
||||
</FrameLayout>
|
||||
|
||||
</android.support.design.widget.CollapsingToolbarLayout>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<RelativeLayout
|
||||
android:id="@+id/detail_content_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?android:windowBackground">
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:windowBackground"
|
||||
app:layout_scrollFlags="scroll">
|
||||
|
||||
<!-- TITLE -->
|
||||
<FrameLayout
|
||||
|
@ -127,7 +136,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_detail_title_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero."/>
|
||||
tools:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum. Nunc eleifend est quis ipsum porttitor egestas. Sed facilisis, nisl quis eleifend pellentesque, orci metus egestas dolor, at accumsan eros metus quis libero." />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_toggle_description_view"
|
||||
|
@ -136,7 +145,7 @@
|
|||
android:layout_gravity="center_vertical|right"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:src="@drawable/arrow_down"
|
||||
tools:ignore="ContentDescription,RtlHardcoded"/>
|
||||
tools:ignore="ContentDescription,RtlHardcoded" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
@ -150,7 +159,7 @@
|
|||
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!--ERROR PANEL-->
|
||||
<include
|
||||
|
@ -161,7 +170,7 @@
|
|||
android:layout_below="@id/detail_title_root_layout"
|
||||
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
|
||||
<!--HIDING ROOT-->
|
||||
<LinearLayout
|
||||
|
@ -189,12 +198,12 @@
|
|||
android:id="@+id/detail_uploader_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toLeftOf="@id/details_panel"
|
||||
android:layout_toStartOf="@id/details_panel"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:padding="6dp"
|
||||
android:layout_toLeftOf="@id/details_panel"
|
||||
android:layout_toStartOf="@id/details_panel">
|
||||
android:padding="6dp">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/detail_uploader_thumbnail_view"
|
||||
|
@ -202,23 +211,23 @@
|
|||
android:layout_height="@dimen/video_item_detail_uploader_image_size"
|
||||
android:contentDescription="@string/detail_uploader_thumbnail_view_description"
|
||||
android:src="@drawable/buddy"
|
||||
tools:ignore="RtlHardcoded"/>
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_uploader_text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="15dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_detail_uploader_text_size"
|
||||
android:textStyle="bold"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:marqueeRepeatLimit="marquee_forever"
|
||||
android:scrollHorizontally="true"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_detail_uploader_text_size"
|
||||
android:textStyle="bold"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="Uploader"/>
|
||||
tools:text="Uploader" />
|
||||
|
||||
<!--<Button
|
||||
android:id="@+id/detail_uploader_subscribe"
|
||||
|
@ -239,10 +248,11 @@
|
|||
android:id="@+id/details_panel"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:paddingLeft="6dp"
|
||||
android:paddingRight="6dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_view_count_view"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -254,7 +264,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_detail_views_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="2,816,821,505 views"/>
|
||||
tools:text="2,816,821,505 views" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbs_up_img_view"
|
||||
|
@ -262,7 +272,7 @@
|
|||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/detail_view_count_view"
|
||||
android:contentDescription="@string/detail_likes_img_view_description"
|
||||
android:src="?attr/thumbs_up"/>
|
||||
android:src="?attr/thumbs_up" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_up_count_view"
|
||||
|
@ -276,7 +286,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12M"/>
|
||||
tools:text="12M" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbs_down_img_view"
|
||||
|
@ -287,7 +297,7 @@
|
|||
android:layout_toRightOf="@id/detail_thumbs_up_count_view"
|
||||
android:contentDescription="@string/detail_dislikes_img_view_description"
|
||||
android:src="?attr/thumbs_down"
|
||||
tools:ignore="RtlHardcoded"/>
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_down_count_view"
|
||||
|
@ -301,7 +311,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="10K"/>
|
||||
tools:text="10K" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_disabled_view"
|
||||
|
@ -317,7 +327,7 @@
|
|||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:visibility="visible"/>
|
||||
tools:visibility="visible" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -337,14 +347,14 @@
|
|||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/append_playlist"
|
||||
android:drawableTop="?attr/ic_playlist_add"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingTop="6dp"
|
||||
android:text="@string/controls_add_to_playlist_title"
|
||||
android:textSize="12sp"/>
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_controls_background"
|
||||
|
@ -354,14 +364,14 @@
|
|||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/play_audio"
|
||||
android:drawableTop="?attr/audio"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingTop="6dp"
|
||||
android:text="@string/controls_background_title"
|
||||
android:textSize="12sp"/>
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_controls_popup"
|
||||
|
@ -371,14 +381,14 @@
|
|||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/open_in_popup_mode"
|
||||
android:drawableTop="?attr/popup"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingTop="6dp"
|
||||
android:text="@string/controls_popup_title"
|
||||
android:textSize="12sp"/>
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_controls_download"
|
||||
|
@ -388,14 +398,14 @@
|
|||
android:layout_weight="1"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:contentDescription="@string/controls_download_desc"
|
||||
android:drawableTop="?attr/download"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:paddingBottom="6dp"
|
||||
android:paddingTop="6dp"
|
||||
android:text="@string/download"
|
||||
android:textSize="12sp"/>
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -404,7 +414,7 @@
|
|||
android:layout_height="1px"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:background="?attr/separator_color"/>
|
||||
android:background="?attr/separator_color" />
|
||||
|
||||
<!--DESCRIPTIONS-->
|
||||
<LinearLayout
|
||||
|
@ -425,7 +435,7 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_upload_date_text_size"
|
||||
android:textStyle="bold"
|
||||
tools:text="Published on Oct 2, 2009"/>
|
||||
tools:text="Published on Oct 2, 2009" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_description_view"
|
||||
|
@ -438,59 +448,41 @@
|
|||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/video_item_detail_description_text_size"
|
||||
tools:text="Description Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum."/>
|
||||
tools:text="Description Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed a ultricies ex. Integer sit amet sodales risus. Duis non mi et urna pretium bibendum." />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1px"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:background="?attr/separator_color"/>
|
||||
android:background="?attr/separator_color" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!--NEXT AND RELATED VIDEOS-->
|
||||
<LinearLayout
|
||||
android:id="@+id/detail_related_streams_root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal|bottom"
|
||||
android:layout_marginTop="14dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_next_stream_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:text="@string/next_video_title"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_next_text_size"
|
||||
tools:ignore="RtlHardcoded"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/detail_related_streams_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="2dp"
|
||||
android:orientation="vertical"
|
||||
tools:minHeight="50dp"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/detail_related_streams_expand"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingTop="4dp"
|
||||
android:src="?attr/expand"
|
||||
android:textAlignment="center"
|
||||
android:textAllCaps="true"
|
||||
tools:ignore="ContentDescription"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</com.nirhart.parallaxscroll.views.ParallaxScrollView>
|
||||
|
||||
</android.support.design.widget.AppBarLayout>
|
||||
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
|
||||
<android.support.design.widget.TabLayout
|
||||
android:id="@+id/tablayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center"
|
||||
android:background="@color/transparent_background_color"
|
||||
app:tabBackground="@drawable/tab_selector"
|
||||
app:tabGravity="center"
|
||||
app:tabIndicatorHeight="0dp">
|
||||
|
||||
</android.support.design.widget.TabLayout>
|
||||
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
</FrameLayout>
|
||||
|
|
115
app/src/main/res/layout/list_comments_item.xml
Normal file
115
app/src/main/res/layout/list_comments_item.xml
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/video_item_search_padding">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/itemThumbnailView"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginRight="@dimen/video_item_search_image_right_margin"
|
||||
android:contentDescription="@string/list_thumbnail_view_description"
|
||||
android:src="@drawable/buddy"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemTitleView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginBottom="@dimen/video_item_search_image_right_margin"
|
||||
android:layout_toEndOf="@+id/itemThumbnailView"
|
||||
android:layout_toRightOf="@+id/itemThumbnailView"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_title_text_size"
|
||||
tools:text="Author Name, Lorem ipsum" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemCommentContentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/itemTitleView"
|
||||
android:layout_marginBottom="@dimen/channel_item_description_to_details_margin"
|
||||
android:layout_toEndOf="@+id/itemThumbnailView"
|
||||
android:layout_toRightOf="@+id/itemThumbnailView"
|
||||
android:ellipsize="end"
|
||||
android:lines="2"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_search_uploader_text_size"
|
||||
tools:text="Comment Content, Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blandit" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbs_up_img_view"
|
||||
android:layout_width="@dimen/video_item_detail_like_image_width"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_toRightOf="@+id/itemThumbnailView"
|
||||
android:contentDescription="@string/detail_likes_img_view_description"
|
||||
android:src="?attr/thumbs_up" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_up_count_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="@dimen/video_item_detail_like_margin"
|
||||
android:layout_toRightOf="@id/detail_thumbs_up_img_view"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12M" />
|
||||
|
||||
|
||||
<!--we can uncomment below code if we need dislike button and count in future-->
|
||||
|
||||
<!--<ImageView
|
||||
android:id="@+id/detail_thumbs_down_img_view"
|
||||
android:layout_width="@dimen/video_item_detail_like_image_width"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_toRightOf="@id/detail_thumbs_up_count_view"
|
||||
android:contentDescription="@string/detail_dislikes_img_view_description"
|
||||
android:src="?attr/thumbs_down"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_down_count_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="@dimen/video_item_detail_like_margin"
|
||||
android:layout_toRightOf="@id/detail_thumbs_down_img_view"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="10K" />-->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemPublishedTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_toRightOf="@id/detail_thumbs_up_count_view"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_upload_date_text_size"
|
||||
tools:text="1 year ago" />
|
||||
|
||||
</RelativeLayout>
|
97
app/src/main/res/layout/list_comments_mini_item.xml
Normal file
97
app/src/main/res/layout/list_comments_mini_item.xml
Normal file
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemRoot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="@dimen/video_item_search_padding">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/itemThumbnailView"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="12dp"
|
||||
android:contentDescription="@string/list_thumbnail_view_description"
|
||||
android:src="@drawable/buddy_channel_item"
|
||||
tools:ignore="RtlHardcoded"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemCommentContentView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/channel_item_description_to_details_margin"
|
||||
android:layout_toRightOf="@+id/itemThumbnailView"
|
||||
android:ellipsize="end"
|
||||
android:lines="2"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_uploader_text_size"
|
||||
tools:text="Channel description, Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blanditLorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc tristique vitae sem vitae blandit" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/detail_thumbs_up_img_view"
|
||||
android:layout_width="@dimen/video_item_detail_like_image_width"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_toRightOf="@+id/itemThumbnailView"
|
||||
android:contentDescription="@string/detail_likes_img_view_description"
|
||||
android:src="?attr/thumbs_up" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_up_count_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="@dimen/video_item_detail_like_margin"
|
||||
android:layout_toRightOf="@id/detail_thumbs_up_img_view"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="12M" />
|
||||
|
||||
<!--we can uncomment below code if we need dislike button and count in future-->
|
||||
|
||||
<!--<ImageView
|
||||
android:id="@+id/detail_thumbs_down_img_view"
|
||||
android:layout_width="@dimen/video_item_detail_like_image_width"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_toRightOf="@id/detail_thumbs_up_count_view"
|
||||
android:contentDescription="@string/detail_dislikes_img_view_description"
|
||||
android:src="?attr/thumbs_down"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/detail_thumbs_down_count_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/video_item_detail_like_image_height"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="@dimen/video_item_detail_like_margin"
|
||||
android:layout_toRightOf="@id/detail_thumbs_down_img_view"
|
||||
android:gravity="center_vertical"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="@dimen/video_item_detail_likes_text_size"
|
||||
tools:ignore="RtlHardcoded"
|
||||
tools:text="10K" />-->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/itemPublishedTime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/itemCommentContentView"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_toRightOf="@id/detail_thumbs_up_count_view"
|
||||
android:lines="1"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_upload_date_text_size"
|
||||
tools:text="1 year ago" />
|
||||
|
||||
</RelativeLayout>
|
32
app/src/main/res/layout/related_streams_header.xml
Normal file
32
app/src/main/res/layout/related_streams_header.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/channel_header_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/next_stream_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="12dp"
|
||||
android:layout_alignBaseline="@+id/autoplay_switch"
|
||||
android:text="@string/next_video_title"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textSize="12sp"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/autoplay_switch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:paddingRight="5dp"
|
||||
android:switchPadding="5dp"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@android:color/tab_indicator_text"
|
||||
android:text="@string/autoplay_title" />
|
||||
|
||||
</RelativeLayout>
|
|
@ -138,6 +138,7 @@
|
|||
<string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string>
|
||||
<string name="show_play_with_kodi_key" translatable="false">show_play_with_kodi</string>
|
||||
<string name="show_next_video_key" translatable="false">show_next_video</string>
|
||||
<string name="show_comments_key" translatable="false">show_comments</string>
|
||||
<string name="show_hold_to_append_key" translatable="false">show_hold_to_append</string>
|
||||
<string name="default_language_value">en</string>
|
||||
<string name="default_country_value">GB</string>
|
||||
|
|
|
@ -77,6 +77,8 @@
|
|||
<string name="use_inexact_seek_summary">Inexact seek allows the player to seek to positions faster with reduced precision</string>
|
||||
<string name="download_thumbnail_title">Load thumbnails</string>
|
||||
<string name="download_thumbnail_summary">When off no thumbnails load, saving data and memory usage. Changes clear both in-memory and on-disk image cache.</string>
|
||||
<string name="show_comments_title">Show comments</string>
|
||||
<string name="show_comments_summary">Disable to stop showing comments</string>
|
||||
<string name="thumbnail_cache_wipe_complete_notice">Image cache wiped</string>
|
||||
<string name="metadata_cache_wipe_title">Wipe cached metadata</string>
|
||||
<string name="metadata_cache_wipe_summary">Remove all cached webpage data</string>
|
||||
|
@ -98,7 +100,8 @@
|
|||
<string name="resume_on_audio_focus_gain_title">Resume on focus gain</string>
|
||||
<string name="resume_on_audio_focus_gain_summary">Continue playing after interruptions (e.g. phone calls)</string>
|
||||
<string name="download_dialog_title">Download</string>
|
||||
<string name="next_video_title">Next</string>
|
||||
<string name="next_video_title">Up next</string>
|
||||
<string name="autoplay_title">Autoplay</string>
|
||||
<string name="show_next_and_similar_title">Show \'Next\' and \'Similar\' videos</string>
|
||||
<string name="show_hold_to_append_title">Show \"Hold to append\" tip</string>
|
||||
<string name="show_hold_to_append_summary">Show tip when background or popup button is pressed on video details page</string>
|
||||
|
@ -135,6 +138,7 @@
|
|||
<string name="playlist">Playlist</string>
|
||||
<string name="playlists">Playlists</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="comments">Comments</string>
|
||||
<string name="tracks">Tracks</string>
|
||||
<string name="users">Users</string>
|
||||
<string name="events">Events</string>
|
||||
|
@ -238,6 +242,7 @@
|
|||
<string name="user_report">User report</string>
|
||||
<string name="search_no_results">No results</string>
|
||||
<string name="empty_view_no_videos" translatable="false">@string/no_videos</string>
|
||||
<string name="empty_view_no_comments" translatable="false">@string/no_comments</string>
|
||||
<string name="empty_subscription_feed_subtitle">Nothing here but crickets</string>
|
||||
<string name="detail_drag_description">Drag to reorder</string>
|
||||
|
||||
|
@ -273,6 +278,12 @@
|
|||
<item quantity="other">%s videos</item>
|
||||
</plurals>
|
||||
|
||||
<string name="no_comments">No comments</string>
|
||||
<plurals name="comments">
|
||||
<item quantity="one">%s comment</item>
|
||||
<item quantity="other">%s comments</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Missions -->
|
||||
<string name="start">Start</string>
|
||||
<string name="pause">Pause</string>
|
||||
|
@ -391,6 +402,7 @@
|
|||
<string name="could_not_import_all_files">Warning: Could not import all files.</string>
|
||||
<string name="override_current_data">This will override your current setup.</string>
|
||||
<string name="import_settings">Do you want to also import settings?</string>
|
||||
<string name="error_unable_to_load_comments">Could not load comments</string>
|
||||
|
||||
<!-- Kiosk Names -->
|
||||
<string name="kiosk">Kiosk</string>
|
||||
|
|
|
@ -41,6 +41,13 @@
|
|||
android:title="@string/download_thumbnail_title"
|
||||
android:summary="@string/download_thumbnail_summary"/>
|
||||
|
||||
<SwitchPreference
|
||||
app:iconSpaceReserved="false"
|
||||
android:defaultValue="true"
|
||||
android:key="@string/show_comments_key"
|
||||
android:title="@string/show_comments_title"
|
||||
android:summary="@string/show_comments_summary"/>
|
||||
|
||||
<Preference
|
||||
app:iconSpaceReserved="false"
|
||||
android:summary="@string/import_data_summary"
|
||||
|
|
Loading…
Reference in a new issue