added viewpager. changed from parallaxscrollview to coordinate layout

This commit is contained in:
Ritvik Saraf 2018-10-02 20:39:16 +05:30
parent e4bef056e6
commit 2e9a860aaa
8 changed files with 484 additions and 528 deletions

View file

@ -0,0 +1,82 @@
package org.schabi.newpipe.fragments.detail;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
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<>();
int baseId = 0;
public TabAdaptor(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
@Override
public long getItemId(int position) {
// give an ID different from position when position has been changed
return baseId + position;
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
notifyDataSetChanged();
}
public void clearAllItems() {
mFragmentList.clear();
mFragmentTitleList.clear();
notifyDataSetChanged();
}
public void removeItem(int position){
mFragmentList.remove(position == 0 ? 0 : position - 1);
mFragmentTitleList.remove(position == 0 ? 0 : position - 1);
notifyDataSetChanged();
}
public void updateItem(int position, Fragment fragment){
mFragmentList.set(position, fragment);
// shift the ID returned by getItemId outside the range of all previous fragments
// https://stackoverflow.com/questions/10396321/remove-fragment-page-from-viewpager-in-android
baseId += getCount() + 1;
notifyDataSetChanged();
}
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;
}
}

View file

@ -13,7 +13,11 @@ import android.support.annotation.DrawableRes;
import android.support.annotation.FloatRange; import android.support.annotation.FloatRange;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; 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.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
@ -40,11 +44,9 @@ import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TabHost;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.nirhart.parallaxscroll.views.ParallaxScrollView;
import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
@ -56,7 +58,6 @@ import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.comments.CommentsInfo; import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException; import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
@ -69,6 +70,8 @@ import org.schabi.newpipe.extractor.stream.StreamType;
import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.stream.VideoStream;
import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BackPressable;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment;
import org.schabi.newpipe.info_list.InfoItemBuilder; import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoItemDialog; import org.schabi.newpipe.info_list.InfoItemDialog;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog; import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
@ -117,13 +120,6 @@ public class VideoDetailFragment
View.OnLongClickListener { View.OnLongClickListener {
public static final String AUTO_PLAY = "auto_play"; public static final String AUTO_PLAY = "auto_play";
// Amount of videos to show on start
private static final int INITIAL_RELATED_VIDEOS = 8;
// Amount of comments to show on start
public static final int INITIAL_COMMENTS = 8;
private InfoItemBuilder infoItemBuilder = null;
private int updateFlags = 0; private int updateFlags = 0;
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1; private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2; private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
@ -133,8 +129,6 @@ public class VideoDetailFragment
private boolean autoPlayEnabled; private boolean autoPlayEnabled;
private boolean showRelatedStreams; private boolean showRelatedStreams;
private boolean showComments; private boolean showComments;
private boolean isCommentsSupported;
private boolean wasRelatedStreamsExpanded = false;
@State @State
protected int serviceId = Constants.NO_SERVICE_ID; protected int serviceId = Constants.NO_SERVICE_ID;
@ -144,7 +138,6 @@ public class VideoDetailFragment
protected String url; protected String url;
private StreamInfo currentInfo; private StreamInfo currentInfo;
private CommentsInfo commentsInfo;
private Disposable currentWorker; private Disposable currentWorker;
@NonNull @NonNull
private CompositeDisposable disposables = new CompositeDisposable(); private CompositeDisposable disposables = new CompositeDisposable();
@ -160,7 +153,6 @@ public class VideoDetailFragment
private Spinner spinnerToolbar; private Spinner spinnerToolbar;
private ParallaxScrollView parallaxScrollRootView;
private LinearLayout contentRootLayoutHiding; private LinearLayout contentRootLayoutHiding;
private View thumbnailBackgroundButton; private View thumbnailBackgroundButton;
@ -193,21 +185,13 @@ public class VideoDetailFragment
private ImageView thumbsDownImageView; private ImageView thumbsDownImageView;
private TextView thumbsDisabledTextView; private TextView thumbsDisabledTextView;
private TextView nextStreamTitle; private static final String COMMENTS_TAB_TAG = "COMMENTS";
private LinearLayout relatedStreamRootLayout; private static final String RELATED_TAB_TAG = "NEXT VIDEO";
private LinearLayout relatedStreamsView;
private ImageButton relatedStreamExpandButton;
private LinearLayout commentsRootLayout;
private View commentsEmptyStateView;
private LinearLayout commentsView;
private ImageButton commentsExpandButton;
private Disposable commentsDisposable;
private TabHost tabHost;
private static final String COMMENTS_TAB_TAG = "CommentsTab";
private static final String RELATED_TAB_TAG = "RelatedTab";
private AppBarLayout appBarLayout;
private ViewPager viewPager;
private TabAdaptor pageAdapter;
private TabLayout tabLayout;
/*////////////////////////////////////////////////////////////////////////*/ /*////////////////////////////////////////////////////////////////////////*/
@ -247,7 +231,6 @@ public class VideoDetailFragment
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
if (currentWorker != null) currentWorker.dispose(); if (currentWorker != null) currentWorker.dispose();
if (commentsDisposable != null) commentsDisposable.dispose();
} }
@Override @Override
@ -256,10 +239,9 @@ public class VideoDetailFragment
if (updateFlags != 0) { if (updateFlags != 0) {
if (!isLoading.get() && currentInfo != null) { if (!isLoading.get() && currentInfo != null) {
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) startLoading(false);
initRelatedVideos(currentInfo);
if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo); if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo);
if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) initComments(commentsInfo); if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) startLoading(false);
} }
if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0
@ -273,8 +255,6 @@ public class VideoDetailFragment
// Check if it was loading when the fragment was stopped/paused, // Check if it was loading when the fragment was stopped/paused,
if (wasLoading.getAndSet(false)) { if (wasLoading.getAndSet(false)) {
selectAndLoadVideo(serviceId, url, name); selectAndLoadVideo(serviceId, url, name);
}else{
loadComments(false);
} }
} }
@ -285,10 +265,8 @@ public class VideoDetailFragment
.unregisterOnSharedPreferenceChangeListener(this); .unregisterOnSharedPreferenceChangeListener(this);
if (currentWorker != null) currentWorker.dispose(); if (currentWorker != null) currentWorker.dispose();
if (commentsDisposable != null) commentsDisposable.dispose();
if (disposables != null) disposables.clear(); if (disposables != null) disposables.clear();
currentWorker = null; currentWorker = null;
commentsDisposable = null;
disposables = null; disposables = null;
} }
@ -339,7 +317,6 @@ public class VideoDetailFragment
private static final String INFO_KEY = "info_key"; private static final String INFO_KEY = "info_key";
private static final String STACK_KEY = "stack_key"; private static final String STACK_KEY = "stack_key";
private static final String WAS_RELATED_EXPANDED_KEY = "was_related_expanded_key";
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
@ -348,10 +325,6 @@ public class VideoDetailFragment
// Check if the next video label and video is visible, // Check if the next video label and video is visible,
// if it is, include the two elements in the next check // if it is, include the two elements in the next check
int nextCount = currentInfo != null && currentInfo.getNextVideo() != null ? 2 : 0; 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()) { if (!isLoading.get() && currentInfo != null && isVisible()) {
outState.putSerializable(INFO_KEY, currentInfo); outState.putSerializable(INFO_KEY, currentInfo);
@ -364,7 +337,6 @@ public class VideoDetailFragment
protected void onRestoreInstanceState(@NonNull Bundle savedState) { protected void onRestoreInstanceState(@NonNull Bundle savedState) {
super.onRestoreInstanceState(savedState); super.onRestoreInstanceState(savedState);
wasRelatedStreamsExpanded = savedState.getBoolean(WAS_RELATED_EXPANDED_KEY, false);
Serializable serializable = savedState.getSerializable(INFO_KEY); Serializable serializable = savedState.getSerializable(INFO_KEY);
if (serializable instanceof StreamInfo) { if (serializable instanceof StreamInfo) {
//noinspection unchecked //noinspection unchecked
@ -432,12 +404,6 @@ public class VideoDetailFragment
case R.id.detail_title_root_layout: case R.id.detail_title_root_layout:
toggleTitleAndDescription(); toggleTitleAndDescription();
break; break;
case R.id.detail_related_streams_expand:
toggleExpandRelatedVideos(currentInfo);
break;
case R.id.detail_comments_expand:
toggleExpandComments(commentsInfo);
break;
} }
} }
@ -472,41 +438,6 @@ public class VideoDetailFragment
} }
} }
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;
}
//Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "], from = [" + INITIAL_RELATED_VIDEOS + "]");
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)));
}
private void toggleExpandComments(CommentsInfo info) {
if (DEBUG) Log.d(TAG, "toggleExpandComments() called with: info = [" + info + "]");
if (!showComments || null == info) return;
NavigationHelper.openCommentsFragment(getFragmentManager(), serviceId, url, name);
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Init // Init
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -516,8 +447,6 @@ public class VideoDetailFragment
super.initViews(rootView, savedInstanceState); super.initViews(rootView, savedInstanceState);
spinnerToolbar = activity.findViewById(R.id.toolbar).findViewById(R.id.toolbar_spinner); 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); thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view); thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button); thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
@ -553,67 +482,21 @@ public class VideoDetailFragment
uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view); uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view);
uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view); uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view);
StreamingService service = null; appBarLayout = rootView.findViewById(R.id.appbarlayout);
try { viewPager = rootView.findViewById(R.id.viewpager);
service = NewPipe.getService(serviceId); pageAdapter = new TabAdaptor(getChildFragmentManager());
} catch (ExtractionException e) { viewPager.setAdapter(pageAdapter);
onError(e); tabLayout = rootView.findViewById(R.id.tablayout);
} tabLayout.setupWithViewPager(viewPager);
if (service.isCommentsSupported()) {
isCommentsSupported = true;
initTabs(rootView);
}
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);
relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand);
commentsRootLayout = rootView.findViewById(R.id.detail_comments_root_layout);
commentsEmptyStateView = rootView.findViewById(R.id.comments_empty_state_view);
commentsView = rootView.findViewById(R.id.detail_comments_view);
commentsExpandButton = rootView.findViewById(R.id.detail_comments_expand);
infoItemBuilder = new InfoItemBuilder(activity);
setHeightThumbnail(); setHeightThumbnail();
} }
private void initTabs(View rootView) {
tabHost = (TabHost) rootView.findViewById(R.id.tab_host);
tabHost.setup();
TabHost.TabSpec commentsTab = tabHost.newTabSpec(COMMENTS_TAB_TAG);
commentsTab.setContent(R.id.detail_comments_root_layout);
commentsTab.setIndicator(getString(R.string.comments));
TabHost.TabSpec relatedVideosTab = tabHost.newTabSpec(RELATED_TAB_TAG);
relatedVideosTab.setContent(R.id.detail_related_streams_root_layout);
relatedVideosTab.setIndicator(getString(R.string.next_video_title));
tabHost.addTab(commentsTab);
tabHost.addTab(relatedVideosTab);
//show comments tab by default
tabHost.setCurrentTabByTag(COMMENTS_TAB_TAG);
}
@Override @Override
protected void initListeners() { protected void initListeners() {
super.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); videoTitleRoot.setOnClickListener(this);
uploaderRootLayout.setOnClickListener(this); uploaderRootLayout.setOnClickListener(this);
@ -623,8 +506,6 @@ public class VideoDetailFragment
detailControlsAddToPlaylist.setOnClickListener(this); detailControlsAddToPlaylist.setOnClickListener(this);
detailControlsDownload.setOnClickListener(this); detailControlsDownload.setOnClickListener(this);
detailControlsDownload.setOnLongClickListener(this); detailControlsDownload.setOnLongClickListener(this);
relatedStreamExpandButton.setOnClickListener(this);
commentsExpandButton.setOnClickListener(this);
detailControlsBackground.setLongClickable(true); detailControlsBackground.setLongClickable(true);
detailControlsPopup.setLongClickable(true); detailControlsPopup.setLongClickable(true);
@ -707,98 +588,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());
showRelatedStreamsIfSelected();
} else nextStreamTitle.setVisibility(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");
showRelatedStreamsIfSelected();
relatedStreamExpandButton.setVisibility(View.VISIBLE);
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
} else {
if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE);
relatedStreamExpandButton.setVisibility(View.GONE);
}
}
private void showRelatedStreamsIfSelected() {
if (null == tabHost || tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) {
relatedStreamRootLayout.setVisibility(View.VISIBLE);
}
}
private void initComments(CommentsInfo info) {
clearComments();
if(null == info || null == info.getRelatedItems() || info.getRelatedItems().size() == 0){
commentsEmptyStateView.setVisibility(View.VISIBLE);
return;
}
commentsEmptyStateView.setVisibility(View.GONE);
List<CommentsInfoItem> initialComments = info.getRelatedItems();
if (null != info && initialComments != null
&& !initialComments.isEmpty() && showComments) {
//long first = System.nanoTime(), each;
int to = initialComments.size() >= INITIAL_COMMENTS
? INITIAL_COMMENTS
: initialComments.size();
for (int i = 0; i < to; i++) {
InfoItem item = initialComments.get(i);
//each = System.nanoTime();
commentsView.addView(infoItemBuilder.buildView(commentsView, 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");
showCommentsIfSelected();
if(initialComments.size() > INITIAL_COMMENTS){
commentsExpandButton.setVisibility(View.VISIBLE);
commentsExpandButton.setImageDrawable(ContextCompat.getDrawable(
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
}else{
commentsExpandButton.setVisibility(View.GONE);
}
} else {
commentsRootLayout.setVisibility(View.GONE);
}
}
private void showCommentsIfSelected() {
if (null == tabHost || tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) {
commentsRootLayout.setVisibility(View.VISIBLE);
}
}
private void clearComments(){
if (commentsView.getChildCount() > 0) commentsView.removeAllViews();
commentsExpandButton.setVisibility(View.GONE);
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Menu // Menu
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -979,23 +768,18 @@ public class VideoDetailFragment
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName());
pushToStack(serviceId, url, name); pushToStack(serviceId, url, name);
showLoading(); showLoading();
initTabs();
Log.d(TAG, "prepareAndHandleInfo() called parallaxScrollRootView.getScrollY(): " if (scrollToTop) appBarLayout.setExpanded(true, true);
+ parallaxScrollRootView.getScrollY());
final boolean greaterThanThreshold = parallaxScrollRootView.getScrollY() > (int)
(getResources().getDisplayMetrics().heightPixels * .1f);
if (scrollToTop) parallaxScrollRootView.smoothScrollTo(0, 0);
animateView(contentRootLayoutHiding, animateView(contentRootLayoutHiding,
false, false, 0, 0, () -> {
greaterThanThreshold ? 250 : 0, 0, () -> {
handleResult(info); handleResult(info);
showContentWithAnimation(120, 0, .01f); showContentWithAnimation(120, 0, .01f);
}); });
} }
protected void prepareAndLoadInfo() { protected void prepareAndLoadInfo() {
parallaxScrollRootView.smoothScrollTo(0, 0); appBarLayout.setExpanded(true, true);
pushToStack(serviceId, url, name); pushToStack(serviceId, url, name);
startLoading(false); startLoading(false);
} }
@ -1004,6 +788,7 @@ public class VideoDetailFragment
public void startLoading(boolean forceLoad) { public void startLoading(boolean forceLoad) {
super.startLoading(forceLoad); super.startLoading(forceLoad);
initTabs();
currentInfo = null; currentInfo = null;
if (currentWorker != null) currentWorker.dispose(); if (currentWorker != null) currentWorker.dispose();
@ -1020,26 +805,29 @@ public class VideoDetailFragment
onError(throwable); onError(throwable);
}); });
loadComments(forceLoad);
} }
private void loadComments(boolean forceLoad) { private void initTabs() {
if(isCommentsSupported && showComments){ pageAdapter.clearAllItems();
clearComments();
commentsInfo = null;
if (commentsDisposable != null) commentsDisposable.dispose();
commentsDisposable = ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad) if(shouldShowComments()){
.subscribeOn(Schedulers.io()) pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG);
.observeOn(AndroidSchedulers.mainThread()) }
.subscribe((@NonNull CommentsInfo result) -> {
commentsInfo = result; if(showRelatedStreams){
showCommentsWithAnimation(120, 0,0); pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG);
initComments(commentsInfo); }
}, (@NonNull Throwable throwable) -> {
onCommentsError(throwable); if(pageAdapter.getCount() < 2){
}); tabLayout.setVisibility(View.GONE);
}
}
private boolean shouldShowComments() {
try {
return showComments && NewPipe.getService(serviceId).isCommentsSupported();
} catch (ExtractionException e) {
return false;
} }
} }
@ -1230,41 +1018,6 @@ public class VideoDetailFragment
.setInterpolator(new FastOutSlowInInterpolator()) .setInterpolator(new FastOutSlowInInterpolator())
.start(); .start();
if (showRelatedStreams && (null == tabHost || tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG))) {
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 showCommentsWithAnimation(long duration,
long delay,
@FloatRange(from = 0.0f, to = 1.0f) float translationPercent) {
int translationY = (int) (getResources().getDisplayMetrics().heightPixels *
(translationPercent > 0.0f ? translationPercent : .06f));
if (showComments && (null == tabHost || tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG))) {
commentsRootLayout.animate().setListener(null).cancel();
commentsRootLayout.setAlpha(0f);
commentsRootLayout.setTranslationY(translationY);
commentsRootLayout.setVisibility(View.VISIBLE);
commentsRootLayout.animate()
.alpha(1f)
.translationY(0)
.setStartDelay((long) (duration * .8f) + delay)
.setDuration(duration)
.setInterpolator(new FastOutSlowInInterpolator())
.start();
}
} }
protected void setInitialData(int serviceId, String url, String name) { protected void setInitialData(int serviceId, String url, String name) {
@ -1324,6 +1077,11 @@ public class VideoDetailFragment
super.handleResult(info); super.handleResult(info);
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName());
if(showRelatedStreams){
pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(currentInfo));
}
pushToStack(serviceId, url, name); pushToStack(serviceId, url, name);
animateView(thumbnailPlayButton, true, 200); animateView(thumbnailPlayButton, true, 200);
@ -1398,12 +1156,6 @@ public class VideoDetailFragment
animateView(spinnerToolbar, true, 500); animateView(spinnerToolbar, true, 500);
setupActionBar(info); setupActionBar(info);
initThumbnailViews(info); initThumbnailViews(info);
initRelatedVideos(info);
if (wasRelatedStreamsExpanded) {
toggleExpandRelatedVideos(currentInfo);
wasRelatedStreamsExpanded = false;
}
setTitleToUrl(info.getServiceId(), info.getUrl(), info.getName()); setTitleToUrl(info.getServiceId(), info.getUrl(), info.getName());
setTitleToUrl(info.getServiceId(), info.getOriginalUrl(), info.getName()); setTitleToUrl(info.getServiceId(), info.getOriginalUrl(), info.getName());

View file

@ -71,7 +71,6 @@ import static org.schabi.newpipe.util.AnimationUtils.animateView;
public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> { public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
private CompositeDisposable disposables = new CompositeDisposable(); private CompositeDisposable disposables = new CompositeDisposable();
private boolean initialLoad = true;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Views // Views
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -94,11 +93,6 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
public void setUserVisibleHint(boolean isVisibleToUser) { public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser); super.setUserVisibleHint(isVisibleToUser);
mIsVisibleToUser = isVisibleToUser; mIsVisibleToUser = isVisibleToUser;
if(activity != null
&& useAsFrontPage
&& isVisibleToUser) {
setTitle(currentInfo != null ? currentInfo.getName() : name);
}
} }
@Override @Override
@ -117,15 +111,6 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
if (disposables != null) disposables.clear(); if (disposables != null) disposables.clear();
} }
/*//////////////////////////////////////////////////////////////////////////
// Init
//////////////////////////////////////////////////////////////////////////*/
/*//////////////////////////////////////////////////////////////////////////
// Menu
//////////////////////////////////////////////////////////////////////////*/
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Load and handle // Load and handle
@ -153,10 +138,6 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
@Override @Override
public void handleResult(@NonNull CommentsInfo result) { public void handleResult(@NonNull CommentsInfo result) {
super.handleResult(result); super.handleResult(result);
if(initialLoad){
itemsList.smoothScrollToPosition(VideoDetailFragment.INITIAL_COMMENTS);
initialLoad = false;
}
if (!result.getErrors().isEmpty()) { if (!result.getErrors().isEmpty()) {
showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); showSnackBarError(result.getErrors(), UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0);
@ -186,12 +167,7 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
protected boolean onError(Throwable exception) { protected boolean onError(Throwable exception) {
if (super.onError(exception)) return true; if (super.onError(exception)) return true;
int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error; showSnackBarError(exception, UserAction.REQUESTED_COMMENTS, NewPipe.getNameOfService(serviceId), url, R.string.error_unable_to_load_comments);
onUnrecoverableError(exception,
UserAction.REQUESTED_COMMENTS,
NewPipe.getNameOfService(serviceId),
url,
errorId);
return true; return true;
} }
@ -201,6 +177,11 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
@Override @Override
public void setTitle(String title) { public void setTitle(String title) {
super.setTitle(title); return;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
return;
} }
} }

View file

@ -0,0 +1,150 @@
package org.schabi.newpipe.fragments.list.videos;
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.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor;
import org.schabi.newpipe.extractor.ListInfo;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.stream.StreamInfo;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.ExtractorHelper;
import org.schabi.newpipe.util.RelatedStreamInfo;
import java.util.List;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable;
public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInfo> {
private CompositeDisposable disposables = new CompositeDisposable();
private RelatedStreamInfo relatedStreamInfo;
/*//////////////////////////////////////////////////////////////////////////
// Views
//////////////////////////////////////////////////////////////////////////*/
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();
}
@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();
}
@Override
public void handleResult(@NonNull RelatedStreamInfo result) {
super.handleResult(result);
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;
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());
this.relatedStreamInfo = RelatedStreamInfo.getInfo(info);
}
}

View file

@ -0,0 +1,23 @@
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 java.util.Collections;
public class RelatedStreamInfo extends ListInfo<InfoItem> {
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());
relatedStreamInfo.setRelatedItems(info.getRelatedStreams());
return relatedStreamInfo;
}
}

View file

@ -25,7 +25,7 @@
android:id="@+id/empty_state_view" android:id="@+id/empty_state_view"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerHorizontal="true"
android:orientation="vertical" android:orientation="vertical"
android:paddingTop="90dp" android:paddingTop="90dp"
android:visibility="gone" android:visibility="gone"

View file

@ -0,0 +1,70 @@
<?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"/>
</RelativeLayout>

View file

@ -7,101 +7,107 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:focusableInTouchMode="true"> android:focusableInTouchMode="true">
<com.nirhart.parallaxscroll.views.ParallaxScrollView <android.support.design.widget.CoordinatorLayout
android:id="@+id/detail_main_content" android:id="@+id/detail_main_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent">
android:visibility="visible"
app:parallax_factor="1.9">
<!--WRAPPER--> <android.support.design.widget.AppBarLayout
<LinearLayout android:id="@+id/appbarlayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:orientation="vertical">
<!-- THUMBNAIL --> <android.support.design.widget.CollapsingToolbarLayout
<FrameLayout
android:id="@+id/detail_thumbnail_root_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/black" app:layout_scrollFlags="scroll">
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground">
<ImageView <!-- THUMBNAIL -->
android:id="@+id/detail_thumbnail_image_view" <FrameLayout
android:id="@+id/detail_thumbnail_root_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/transparent" android:background="@android:color/black"
android:contentDescription="@string/detail_thumbnail_view_description" android:clickable="true"
android:scaleType="fitCenter" android:focusable="true"
tools:ignore="RtlHardcoded" android:foreground="?attr/selectableItemBackground"
tools:layout_height="200dp" app:layout_collapseMode="parallax">
tools:src="@drawable/dummy_thumbnail" />
<ImageView <ImageView
android:id="@+id/detail_thumbnail_play_button" android:id="@+id/detail_thumbnail_image_view"
android:layout_width="64dp" android:layout_width="match_parent"
android:layout_height="64dp" android:layout_height="wrap_content"
android:layout_gravity="center" android:background="@android:color/transparent"
android:background="@android:color/transparent" android:contentDescription="@string/detail_thumbnail_view_description"
android:src="@drawable/new_play_arrow" android:scaleType="fitCenter"
android:visibility="invisible" tools:ignore="RtlHardcoded"
tools:ignore="ContentDescription" tools:layout_height="200dp"
tools:visibility="visible" /> tools:src="@drawable/dummy_thumbnail" />
<TextView <ImageView
android:id="@+id/touch_append_detail" android:id="@+id/detail_thumbnail_play_button"
android:layout_width="wrap_content" android:layout_width="64dp"
android:layout_height="wrap_content" android:layout_height="64dp"
android:layout_gravity="center" android:layout_gravity="center"
android:background="#64000000" android:background="@android:color/transparent"
android:paddingBottom="10dp" android:src="@drawable/new_play_arrow"
android:paddingLeft="30dp" android:visibility="invisible"
android:paddingRight="30dp" tools:ignore="ContentDescription"
android:paddingTop="10dp" tools:visibility="visible" />
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 <TextView
android:id="@+id/detail_duration_view" android:id="@+id/touch_append_detail"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="bottom|right" android:layout_gravity="center"
android:layout_marginBottom="8dp" android:background="#64000000"
android:layout_marginLeft="12dp" android:paddingBottom="10dp"
android:layout_marginRight="12dp" android:paddingLeft="30dp"
android:layout_marginTop="8dp" android:paddingRight="30dp"
android:alpha=".6" android:paddingTop="10dp"
android:background="#23000000" android:text="@string/hold_to_append"
android:gravity="center" android:textColor="@android:color/white"
android:paddingBottom="2dp" android:textSize="20sp"
android:paddingLeft="6dp" android:textStyle="bold"
android:paddingRight="6dp" android:visibility="gone"
android:paddingTop="2dp" tools:ignore="RtlHardcoded"
android:textAllCaps="true" tools:visibility="visible" />
android:textColor="@android:color/white"
android:textSize="12sp" <TextView
android:textStyle="bold" android:id="@+id/detail_duration_view"
android:visibility="gone" android:layout_width="wrap_content"
tools:ignore="RtlHardcoded" android:layout_height="wrap_content"
tools:text="12:38" android:layout_gravity="bottom|right"
tools:visibility="visible" /> android:layout_marginBottom="8dp"
</FrameLayout> 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 --> <!-- CONTENT -->
<RelativeLayout <RelativeLayout
android:id="@+id/detail_content_root_layout" android:id="@+id/detail_content_root_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:background="?android:windowBackground"> android:background="?android:windowBackground"
app:layout_scrollFlags="scroll">
<!-- TITLE --> <!-- TITLE -->
<FrameLayout <FrameLayout
@ -449,132 +455,24 @@
</LinearLayout> </LinearLayout>
<TabHost
android:id="@+id/tab_host"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<!--COMMENTS-->
<LinearLayout
android:id="@+id/detail_comments_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">
<LinearLayout
android:id="@+id/comments_empty_state_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical"
android:paddingTop="65dp"
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="18sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/detail_comments_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_comments_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"
android:visibility="gone"
tools:ignore="ContentDescription" />
</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>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>
</LinearLayout>
</com.nirhart.parallaxscroll.views.ParallaxScrollView> <android.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="?android:windowBackground">
</android.support.design.widget.TabLayout>
</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.CoordinatorLayout>
</FrameLayout> </FrameLayout>