added basic/crappy comments support

This commit is contained in:
Ritvik Saraf 2018-09-03 04:52:59 +05:30
parent 784e01347c
commit 08127e5806
14 changed files with 834 additions and 129 deletions

View File

@ -55,7 +55,7 @@ dependencies {
exclude module: 'support-annotations' exclude module: 'support-annotations'
} }
implementation 'com.github.TeamNewPipe:NewPipeExtractor:217d13b1028' implementation 'com.github.yausername:NewPipeExtractor:5242bda'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:2.8.9' testImplementation 'org.mockito:mockito-core:2.8.9'

View File

@ -3,17 +3,22 @@ package org.schabi.newpipe;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.text.TextUtils; import android.text.TextUtils;
import org.schabi.newpipe.extractor.DownloadResponse;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serializable;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import okhttp3.MediaType;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
@ -137,13 +142,16 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
private ResponseBody getBody(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException { private ResponseBody getBody(String siteUrl, Map<String, String> customProperties) throws IOException, ReCaptchaException {
final Request.Builder requestBuilder = new Request.Builder() final Request.Builder requestBuilder = new Request.Builder()
.method("GET", null).url(siteUrl) .method("GET", null).url(siteUrl);
.addHeader("User-Agent", USER_AGENT);
for (Map.Entry<String, String> header : customProperties.entrySet()) { for (Map.Entry<String, String> header : customProperties.entrySet()) {
requestBuilder.addHeader(header.getKey(), header.getValue()); requestBuilder.addHeader(header.getKey(), header.getValue());
} }
if (!customProperties.containsKey("User-Agent")) {
requestBuilder.header("User-Agent", USER_AGENT);
}
if (!TextUtils.isEmpty(mCookies)) { if (!TextUtils.isEmpty(mCookies)) {
requestBuilder.addHeader("Cookie", mCookies); requestBuilder.addHeader("Cookie", mCookies);
} }
@ -175,4 +183,91 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader {
public String download(String siteUrl) throws IOException, ReCaptchaException { public String download(String siteUrl) throws IOException, ReCaptchaException {
return download(siteUrl, Collections.emptyMap()); return download(siteUrl, Collections.emptyMap());
} }
@Override
public DownloadResponse get(String siteUrl, Map<String, List<String>> requestHeaders) throws IOException, ReCaptchaException {
final Request.Builder requestBuilder = new Request.Builder()
.method("GET", null).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 request = requestBuilder.build();
final Response response = client.newCall(request).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, Collections.emptyMap());
}
@Override
public DownloadResponse post(String siteUrl, String requestBody, Map<String, List<String>> requestHeaders) throws IOException, ReCaptchaException {
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 = RequestBody.create(MediaType.parse(contentType), requestBody);
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 request = requestBuilder.build();
final Response response = client.newCall(request).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());
}
} }

View File

@ -40,6 +40,7 @@ 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;
@ -53,6 +54,7 @@ import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
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.ParsingException; import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
@ -64,19 +66,17 @@ 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.local.history.HistoryRecordManager;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.StreamItemAdapter;
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
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.history.HistoryRecordManager;
import org.schabi.newpipe.player.MainVideoPlayer; import org.schabi.newpipe.player.MainVideoPlayer;
import org.schabi.newpipe.player.PopupVideoPlayer; import org.schabi.newpipe.player.PopupVideoPlayer;
import org.schabi.newpipe.player.helper.PlayerHelper; import org.schabi.newpipe.player.helper.PlayerHelper;
import org.schabi.newpipe.player.old.PlayVideoActivity; import org.schabi.newpipe.player.old.PlayVideoActivity;
import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueue;
import org.schabi.newpipe.player.playqueue.SinglePlayQueue; import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.report.UserAction;
import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.Constants;
import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ExtractorHelper;
@ -87,6 +87,8 @@ import org.schabi.newpipe.util.Localization;
import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.NavigationHelper;
import org.schabi.newpipe.util.OnClickGesture; import org.schabi.newpipe.util.OnClickGesture;
import org.schabi.newpipe.util.PermissionHelper; 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 org.schabi.newpipe.util.ThemeHelper;
import java.io.Serializable; import java.io.Serializable;
@ -114,6 +116,8 @@ public class VideoDetailFragment
// Amount of videos to show on start // Amount of videos to show on start
private static final int INITIAL_RELATED_VIDEOS = 8; private static final int INITIAL_RELATED_VIDEOS = 8;
// Amount of comments to show on start
private static final int INITIAL_COMMENTS = 8;
private InfoItemBuilder infoItemBuilder = null; private InfoItemBuilder infoItemBuilder = null;
@ -121,18 +125,24 @@ public class VideoDetailFragment
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;
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4; private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
private static final int COMMENTS_UPDATE_FLAG = 0x4;
private boolean autoPlayEnabled; private boolean autoPlayEnabled;
private boolean showRelatedStreams; private boolean showRelatedStreams;
private boolean showComments;
private boolean wasRelatedStreamsExpanded = false; private boolean wasRelatedStreamsExpanded = false;
@State protected int serviceId = Constants.NO_SERVICE_ID; @State
@State protected String name; protected int serviceId = Constants.NO_SERVICE_ID;
@State protected String url; @State
protected String name;
@State
protected String url;
private StreamInfo currentInfo; private StreamInfo currentInfo;
private Disposable currentWorker; private Disposable currentWorker;
@NonNull private CompositeDisposable disposables = new CompositeDisposable(); @NonNull
private CompositeDisposable disposables = new CompositeDisposable();
private List<VideoStream> sortedVideoStreams; private List<VideoStream> sortedVideoStreams;
private int selectedVideoStreamIndex = -1; private int selectedVideoStreamIndex = -1;
@ -183,6 +193,16 @@ public class VideoDetailFragment
private LinearLayout relatedStreamsView; private LinearLayout relatedStreamsView;
private ImageButton relatedStreamExpandButton; private ImageButton relatedStreamExpandButton;
private LinearLayout commentsRootLayout;
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";
/*////////////////////////////////////////////////////////////////////////*/ /*////////////////////////////////////////////////////////////////////////*/
@ -197,12 +217,17 @@ public class VideoDetailFragment
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void
onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setHasOptionsMenu(true); setHasOptionsMenu(true);
showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity) showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(getString(R.string.show_next_video_key), true); .getBoolean(getString(R.string.show_next_video_key), true);
showComments = PreferenceManager.getDefaultSharedPreferences(activity)
.getBoolean(getString(R.string.show_comments), true);
PreferenceManager.getDefaultSharedPreferences(activity) PreferenceManager.getDefaultSharedPreferences(activity)
.registerOnSharedPreferenceChangeListener(this); .registerOnSharedPreferenceChangeListener(this);
} }
@ -224,14 +249,17 @@ 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) initRelatedVideos(currentInfo); if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0)
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(currentInfo);
} }
if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0 if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0
&& menu != null) { && menu != null) {
updateMenuItemVisibility(); updateMenuItemVisibility();
} }
updateFlags = 0; updateFlags = 0;
} }
@ -288,6 +316,9 @@ public class VideoDetailFragment
updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG; updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG;
} else if (key.equals(getString(R.string.show_play_with_kodi_key))) { } else if (key.equals(getString(R.string.show_play_with_kodi_key))) {
updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG; updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG;
} else if (key.equals(R.string.show_comments)) {
showComments = sharedPreferences.getBoolean(key, true);
updateFlags |= COMMENTS_UPDATE_FLAG;
} }
} }
@ -312,7 +343,8 @@ public class VideoDetailFragment
} }
if (!isLoading.get() && currentInfo != null && isVisible()) { if (!isLoading.get() && currentInfo != null && isVisible()) {
outState.putSerializable(INFO_KEY, currentInfo); //TODO fix this. it should not be commented
//outState.putSerializable(INFO_KEY, currentInfo);
} }
outState.putSerializable(STACK_KEY, stack); outState.putSerializable(STACK_KEY, stack);
@ -392,6 +424,9 @@ public class VideoDetailFragment
case R.id.detail_related_streams_expand: case R.id.detail_related_streams_expand:
toggleExpandRelatedVideos(currentInfo); toggleExpandRelatedVideos(currentInfo);
break; break;
case R.id.detail_comments_expand:
toggleExpandComments(currentInfo);
break;
} }
} }
@ -452,6 +487,46 @@ public class VideoDetailFragment
ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse))); ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse)));
} }
private void toggleExpandComments(StreamInfo info) {
if (DEBUG) Log.d(TAG, "toggleExpandComments() called with: info = [" + info + "]");
if (!showComments) return;
int initialCount = INITIAL_COMMENTS;
if (commentsView.getChildCount() > initialCount && commentsView.getChildCount() >= info.getComments().size() && !info.hasMoreComments()) {
commentsView.removeViews(initialCount,
commentsView.getChildCount() - (initialCount));
commentsExpandButton.setImageDrawable(ContextCompat.getDrawable(
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
return;
}
//Log.d(TAG, "toggleExpandRelatedVideos() called with: info = [" + info + "], from = [" + INITIAL_RELATED_VIDEOS + "]");
int currentCount = commentsView.getChildCount();
for (int i = currentCount; i < info.getComments().size(); i++) {
CommentsInfoItem item = info.getComments().get(i);
//Log.d(TAG, "i = " + i);
commentsView.addView(infoItemBuilder.buildView(commentsView, item));
}
if (info.hasMoreComments()) {
loadMoreComments(info);
} else {
commentsExpandButton.setImageDrawable(
ContextCompat.getDrawable(activity,
ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.collapse)));
}
}
private void loadMoreComments(StreamInfo info) {
if (commentsDisposable != null) commentsDisposable.dispose();
commentsDisposable = Single.fromCallable(() -> {
StreamInfo.loadMoreComments(info);
return info.getComments();
}).subscribeOn(Schedulers.io()).doOnError(e -> info.addError(e)).subscribe();
}
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Init // Init
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -498,14 +573,37 @@ 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);
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);
relatedStreamRootLayout = rootView.findViewById(R.id.detail_related_streams_root_layout); relatedStreamRootLayout = rootView.findViewById(R.id.detail_related_streams_root_layout);
nextStreamTitle = rootView.findViewById(R.id.detail_next_stream_title); nextStreamTitle = rootView.findViewById(R.id.detail_next_stream_title);
relatedStreamsView = rootView.findViewById(R.id.detail_related_streams_view); relatedStreamsView = rootView.findViewById(R.id.detail_related_streams_view);
relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand); relatedStreamExpandButton = rootView.findViewById(R.id.detail_related_streams_expand);
commentsRootLayout = rootView.findViewById(R.id.detail_comments_root_layout);
commentsView = rootView.findViewById(R.id.detail_comments_view);
commentsExpandButton = rootView.findViewById(R.id.detail_comments_expand);
infoItemBuilder = new InfoItemBuilder(activity); infoItemBuilder = new InfoItemBuilder(activity);
setHeightThumbnail(); setHeightThumbnail();
} }
@Override @Override
@ -532,6 +630,7 @@ public class VideoDetailFragment
detailControlsDownload.setOnClickListener(this); detailControlsDownload.setOnClickListener(this);
detailControlsDownload.setOnLongClickListener(this); detailControlsDownload.setOnLongClickListener(this);
relatedStreamExpandButton.setOnClickListener(this); relatedStreamExpandButton.setOnClickListener(this);
commentsExpandButton.setOnClickListener(this);
detailControlsBackground.setLongClickable(true); detailControlsBackground.setLongClickable(true);
detailControlsPopup.setLongClickable(true); detailControlsPopup.setLongClickable(true);
@ -622,7 +721,7 @@ public class VideoDetailFragment
relatedStreamsView.addView( relatedStreamsView.addView(
infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo())); infoItemBuilder.buildView(relatedStreamsView, info.getNextVideo()));
relatedStreamsView.addView(getSeparatorView()); relatedStreamsView.addView(getSeparatorView());
relatedStreamRootLayout.setVisibility(View.VISIBLE); showRelatedStreamsIfSelected();
} else nextStreamTitle.setVisibility(View.GONE); } else nextStreamTitle.setVisibility(View.GONE);
if (info.getRelatedStreams() != null if (info.getRelatedStreams() != null
@ -639,7 +738,7 @@ public class VideoDetailFragment
} }
//if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms"); //if (DEBUG) Log.d(TAG, "Total time " + ((System.nanoTime() - first) / 1000000L) + "ms");
relatedStreamRootLayout.setVisibility(View.VISIBLE); showRelatedStreamsIfSelected();
relatedStreamExpandButton.setVisibility(View.VISIBLE); relatedStreamExpandButton.setVisibility(View.VISIBLE);
relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable( relatedStreamExpandButton.setImageDrawable(ContextCompat.getDrawable(
@ -648,6 +747,47 @@ public class VideoDetailFragment
if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE); if (info.getNextVideo() == null) relatedStreamRootLayout.setVisibility(View.GONE);
relatedStreamExpandButton.setVisibility(View.GONE); relatedStreamExpandButton.setVisibility(View.GONE);
} }
}
private void showRelatedStreamsIfSelected() {
if (tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) {
relatedStreamRootLayout.setVisibility(View.VISIBLE);
}
}
private void initComments(StreamInfo info) {
if (commentsView.getChildCount() > 0) commentsView.removeAllViews();
if (info.getComments() != null
&& !info.getComments().isEmpty() && showComments) {
//long first = System.nanoTime(), each;
int to = info.getComments().size() >= INITIAL_RELATED_VIDEOS
? INITIAL_RELATED_VIDEOS
: info.getComments().size();
for (int i = 0; i < to; i++) {
InfoItem item = info.getComments().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();
commentsExpandButton.setVisibility(View.VISIBLE);
commentsExpandButton.setImageDrawable(ContextCompat.getDrawable(
activity, ThemeHelper.resolveResourceIdFromAttr(activity, R.attr.expand)));
} else {
commentsRootLayout.setVisibility(View.GONE);
}
}
private void showCommentsIfSelected() {
if (tabHost.getCurrentTabTag().contentEquals(COMMENTS_TAB_TAG)) {
commentsRootLayout.setVisibility(View.VISIBLE);
}
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -682,7 +822,7 @@ public class VideoDetailFragment
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if(isLoading.get()) { if (isLoading.get()) {
// if is still loading block menu // if is still loading block menu
return true; return true;
} }
@ -706,7 +846,7 @@ public class VideoDetailFragment
NavigationHelper.playWithKore(activity, Uri.parse( NavigationHelper.playWithKore(activity, Uri.parse(
url.replace("https", "http"))); url.replace("https", "http")));
} catch (Exception e) { } 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); showInstallKoreDialog(activity);
} }
return true; return true;
@ -720,7 +860,8 @@ public class VideoDetailFragment
builder.setMessage(R.string.kore_not_found) builder.setMessage(R.string.kore_not_found)
.setPositiveButton(R.string.install, (DialogInterface dialog, int which) -> .setPositiveButton(R.string.install, (DialogInterface dialog, int which) ->
NavigationHelper.installKore(context)) NavigationHelper.installKore(context))
.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {}); .setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
});
builder.create().show(); builder.create().show();
} }
@ -823,7 +964,8 @@ public class VideoDetailFragment
} }
public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) { public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
if (DEBUG) Log.d(TAG, "prepareAndHandleInfo() called with: info = [" + info + "], scrollToTop = [" + scrollToTop + "]"); if (DEBUG)
Log.d(TAG, "prepareAndHandleInfo() called with: info = [" + info + "], scrollToTop = [" + scrollToTop + "]");
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName()); setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName());
pushToStack(serviceId, url, name); pushToStack(serviceId, url, name);
@ -1057,7 +1199,7 @@ public class VideoDetailFragment
.setInterpolator(new FastOutSlowInInterpolator()) .setInterpolator(new FastOutSlowInInterpolator())
.start(); .start();
if (showRelatedStreams) { if (showRelatedStreams && tabHost.getCurrentTabTag().contentEquals(RELATED_TAB_TAG)) {
relatedStreamRootLayout.animate().setListener(null).cancel(); relatedStreamRootLayout.animate().setListener(null).cancel();
relatedStreamRootLayout.setAlpha(0f); relatedStreamRootLayout.setAlpha(0f);
relatedStreamRootLayout.setTranslationY(translationY); relatedStreamRootLayout.setTranslationY(translationY);
@ -1070,6 +1212,20 @@ public class VideoDetailFragment
.setInterpolator(new FastOutSlowInInterpolator()) .setInterpolator(new FastOutSlowInInterpolator())
.start(); .start();
} }
if (showComments && 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) {
@ -1204,6 +1360,8 @@ public class VideoDetailFragment
setupActionBar(info); setupActionBar(info);
initThumbnailViews(info); initThumbnailViews(info);
initRelatedVideos(info); initRelatedVideos(info);
initComments(info);
if (wasRelatedStreamsExpanded) { if (wasRelatedStreamsExpanded) {
toggleExpandRelatedVideos(currentInfo); toggleExpandRelatedVideos(currentInfo);
wasRelatedStreamsExpanded = false; wasRelatedStreamsExpanded = false;

View File

@ -17,6 +17,7 @@ import android.view.View;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; 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.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.fragments.BaseStateFragment; import org.schabi.newpipe.fragments.BaseStateFragment;
@ -181,6 +182,13 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I> implem
} }
}); });
infoListAdapter.setOnCommentsSelectedListener(new OnClickGesture<CommentsInfoItem>() {
@Override
public void selected(CommentsInfoItem selectedItem) {
//Log.d("comments" , "this comment was clicked" + selectedItem.getCommentText());
}
});
itemsList.clearOnScrollListeners(); itemsList.clearOnScrollListeners();
itemsList.addOnScrollListener(new OnScrollBelowItemsListener() { itemsList.addOnScrollListener(new OnScrollBelowItemsListener() {
@Override @Override

View File

@ -10,10 +10,13 @@ import com.nostra13.universalimageloader.core.ImageLoader;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; 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.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder; 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.InfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
@ -50,6 +53,7 @@ public class InfoItemBuilder {
private OnClickGesture<StreamInfoItem> onStreamSelectedListener; private OnClickGesture<StreamInfoItem> onStreamSelectedListener;
private OnClickGesture<ChannelInfoItem> onChannelSelectedListener; private OnClickGesture<ChannelInfoItem> onChannelSelectedListener;
private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener; private OnClickGesture<PlaylistInfoItem> onPlaylistSelectedListener;
private OnClickGesture<CommentsInfoItem> onCommentsSelectedListener;
public InfoItemBuilder(Context context) { public InfoItemBuilder(Context context) {
this.context = context; this.context = context;
@ -73,6 +77,8 @@ public class InfoItemBuilder {
return useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) : new ChannelInfoItemHolder(this, parent); return useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) : new ChannelInfoItemHolder(this, parent);
case PLAYLIST: case PLAYLIST:
return useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) : new PlaylistInfoItemHolder(this, parent); return useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) : new PlaylistInfoItemHolder(this, parent);
case COMMENT:
return useMiniVariant ? new CommentsMiniInfoItemHolder(this, parent) : new CommentsInfoItemHolder(this, parent);
default: default:
Log.e(TAG, "Trollolo"); Log.e(TAG, "Trollolo");
throw new RuntimeException("InfoType not expected = " + infoType.name()); throw new RuntimeException("InfoType not expected = " + infoType.name());
@ -111,4 +117,12 @@ public class InfoItemBuilder {
this.onPlaylistSelectedListener = listener; this.onPlaylistSelectedListener = listener;
} }
public OnClickGesture<CommentsInfoItem> getOnCommentsSelectedListener() {
return onCommentsSelectedListener;
}
public void setOnCommentsSelectedListener(OnClickGesture<CommentsInfoItem> onCommentsSelectedListener) {
this.onCommentsSelectedListener = onCommentsSelectedListener;
}
} }

View File

@ -8,6 +8,7 @@ import android.view.ViewGroup;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.channel.ChannelInfoItem; 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.playlist.PlaylistInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
@ -90,6 +91,10 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
infoItemBuilder.setOnPlaylistSelectedListener(listener); infoItemBuilder.setOnPlaylistSelectedListener(listener);
} }
public void setOnCommentsSelectedListener(OnClickGesture<CommentsInfoItem> listener) {
infoItemBuilder.setOnCommentsSelectedListener(listener);
}
public void useMiniItemVariants(boolean useMiniVariant) { public void useMiniItemVariants(boolean useMiniVariant) {
this.useMiniVariant = useMiniVariant; this.useMiniVariant = useMiniVariant;
} }

View File

@ -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());
}
}

View File

@ -0,0 +1,92 @@
package org.schabi.newpipe.info_list.holder;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
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.Localization;
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 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);
itemContentView = itemView.findViewById(R.id.itemCommentContentView);
itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view);
itemDislikesCountView = itemView.findViewById(R.id.detail_thumbs_down_count_view);
}
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);
}
}
});
itemContentView.setText(item.getCommentText());
if (null != item.getLikeCount()) {
itemLikesCountView.setText(String.valueOf(item.getLikeCount()));
}
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);
}
}
}

View File

@ -59,7 +59,7 @@ public final class ExtractorHelper {
} }
private static void checkServiceId(int serviceId) { 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"); throw new IllegalArgumentException("serviceId is NO_SERVICE_ID");
} }
} }

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/video_item_detail" android:id="@+id/video_item_detail"
@ -40,7 +39,7 @@
android:scaleType="fitCenter" android:scaleType="fitCenter"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:layout_height="200dp" tools:layout_height="200dp"
tools:src="@drawable/dummy_thumbnail"/> tools:src="@drawable/dummy_thumbnail" />
<ImageView <ImageView
android:id="@+id/detail_thumbnail_play_button" android:id="@+id/detail_thumbnail_play_button"
@ -51,25 +50,25 @@
android:src="@drawable/new_play_arrow" android:src="@drawable/new_play_arrow"
android:visibility="invisible" android:visibility="invisible"
tools:ignore="ContentDescription" tools:ignore="ContentDescription"
tools:visibility="visible"/> tools:visibility="visible" />
<TextView <TextView
android:id="@+id/touch_append_detail" 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="center"
android:background="#64000000" android:background="#64000000"
android:paddingBottom="10dp" android:paddingBottom="10dp"
android:paddingLeft="30dp" android:paddingLeft="30dp"
android:paddingRight="30dp" android:paddingRight="30dp"
android:paddingTop="10dp" android:paddingTop="10dp"
android:layout_gravity="center" android:text="@string/hold_to_append"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="20sp" android:textSize="20sp"
android:textStyle="bold" android:textStyle="bold"
android:text="@string/hold_to_append"
android:visibility="gone" android:visibility="gone"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:visibility="visible"/> tools:visibility="visible" />
<TextView <TextView
android:id="@+id/detail_duration_view" android:id="@+id/detail_duration_view"
@ -94,7 +93,7 @@
android:visibility="gone" android:visibility="gone"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:text="12:38" tools:text="12:38"
tools:visibility="visible"/> tools:visibility="visible" />
</FrameLayout> </FrameLayout>
<!-- CONTENT --> <!-- CONTENT -->
@ -127,7 +126,7 @@
android:textAppearance="?android:attr/textAppearanceLarge" android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/video_item_detail_title_text_size" android:textSize="@dimen/video_item_detail_title_text_size"
tools:ignore="RtlHardcoded" 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 <ImageView
android:id="@+id/detail_toggle_description_view" android:id="@+id/detail_toggle_description_view"
@ -136,7 +135,7 @@
android:layout_gravity="center_vertical|right" android:layout_gravity="center_vertical|right"
android:layout_marginLeft="5dp" android:layout_marginLeft="5dp"
android:src="@drawable/arrow_down" android:src="@drawable/arrow_down"
tools:ignore="ContentDescription,RtlHardcoded"/> tools:ignore="ContentDescription,RtlHardcoded" />
</FrameLayout> </FrameLayout>
@ -150,7 +149,7 @@
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin" android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
android:indeterminate="true" android:indeterminate="true"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"/> tools:visibility="visible" />
<!--ERROR PANEL--> <!--ERROR PANEL-->
<include <include
@ -161,7 +160,7 @@
android:layout_below="@id/detail_title_root_layout" android:layout_below="@id/detail_title_root_layout"
android:layout_marginTop="@dimen/video_item_detail_error_panel_margin" android:layout_marginTop="@dimen/video_item_detail_error_panel_margin"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible"/> tools:visibility="visible" />
<!--HIDING ROOT--> <!--HIDING ROOT-->
<LinearLayout <LinearLayout
@ -189,12 +188,12 @@
android:id="@+id/detail_uploader_root_layout" android:id="@+id/detail_uploader_root_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_toLeftOf="@id/details_panel"
android:layout_toStartOf="@id/details_panel"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal" android:orientation="horizontal"
android:padding="6dp" android:padding="6dp">
android:layout_toLeftOf="@id/details_panel"
android:layout_toStartOf="@id/details_panel">
<de.hdodenhof.circleimageview.CircleImageView <de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/detail_uploader_thumbnail_view" android:id="@+id/detail_uploader_thumbnail_view"
@ -202,23 +201,23 @@
android:layout_height="@dimen/video_item_detail_uploader_image_size" android:layout_height="@dimen/video_item_detail_uploader_image_size"
android:contentDescription="@string/detail_uploader_thumbnail_view_description" android:contentDescription="@string/detail_uploader_thumbnail_view_description"
android:src="@drawable/buddy" android:src="@drawable/buddy"
tools:ignore="RtlHardcoded"/> tools:ignore="RtlHardcoded" />
<TextView <TextView
android:id="@+id/detail_uploader_text_view" android:id="@+id/detail_uploader_text_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="15dp" 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:ellipsize="marquee"
android:fadingEdge="horizontal" android:fadingEdge="horizontal"
android:marqueeRepeatLimit="marquee_forever" android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true" android:scrollHorizontally="true"
android:singleLine="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:ignore="RtlHardcoded"
tools:text="Uploader"/> tools:text="Uploader" />
<!--<Button <!--<Button
android:id="@+id/detail_uploader_subscribe" android:id="@+id/detail_uploader_subscribe"
@ -239,10 +238,11 @@
android:id="@+id/details_panel" android:id="@+id/details_panel"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:paddingLeft="6dp" android:paddingLeft="6dp"
android:paddingRight="6dp"> android:paddingRight="6dp">
<TextView <TextView
android:id="@+id/detail_view_count_view" android:id="@+id/detail_view_count_view"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -254,7 +254,7 @@
android:textAppearance="?android:attr/textAppearanceLarge" android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/video_item_detail_views_text_size" android:textSize="@dimen/video_item_detail_views_text_size"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:text="2,816,821,505 views"/> tools:text="2,816,821,505 views" />
<ImageView <ImageView
android:id="@+id/detail_thumbs_up_img_view" android:id="@+id/detail_thumbs_up_img_view"
@ -262,7 +262,7 @@
android:layout_height="@dimen/video_item_detail_like_image_height" android:layout_height="@dimen/video_item_detail_like_image_height"
android:layout_below="@id/detail_view_count_view" android:layout_below="@id/detail_view_count_view"
android:contentDescription="@string/detail_likes_img_view_description" android:contentDescription="@string/detail_likes_img_view_description"
android:src="?attr/thumbs_up"/> android:src="?attr/thumbs_up" />
<TextView <TextView
android:id="@+id/detail_thumbs_up_count_view" android:id="@+id/detail_thumbs_up_count_view"
@ -276,7 +276,7 @@
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/video_item_detail_likes_text_size" android:textSize="@dimen/video_item_detail_likes_text_size"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:text="12M"/> tools:text="12M" />
<ImageView <ImageView
android:id="@+id/detail_thumbs_down_img_view" android:id="@+id/detail_thumbs_down_img_view"
@ -287,7 +287,7 @@
android:layout_toRightOf="@id/detail_thumbs_up_count_view" android:layout_toRightOf="@id/detail_thumbs_up_count_view"
android:contentDescription="@string/detail_dislikes_img_view_description" android:contentDescription="@string/detail_dislikes_img_view_description"
android:src="?attr/thumbs_down" android:src="?attr/thumbs_down"
tools:ignore="RtlHardcoded"/> tools:ignore="RtlHardcoded" />
<TextView <TextView
android:id="@+id/detail_thumbs_down_count_view" android:id="@+id/detail_thumbs_down_count_view"
@ -301,7 +301,7 @@
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/video_item_detail_likes_text_size" android:textSize="@dimen/video_item_detail_likes_text_size"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:text="10K"/> tools:text="10K" />
<TextView <TextView
android:id="@+id/detail_thumbs_disabled_view" android:id="@+id/detail_thumbs_disabled_view"
@ -317,7 +317,7 @@
android:textStyle="bold" android:textStyle="bold"
android:visibility="gone" android:visibility="gone"
tools:ignore="RtlHardcoded" tools:ignore="RtlHardcoded"
tools:visibility="visible"/> tools:visibility="visible" />
</RelativeLayout> </RelativeLayout>
</RelativeLayout> </RelativeLayout>
@ -337,14 +337,14 @@
android:layout_weight="1" android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:contentDescription="@string/append_playlist" android:contentDescription="@string/append_playlist"
android:drawableTop="?attr/ic_playlist_add" android:drawableTop="?attr/ic_playlist_add"
android:focusable="true"
android:gravity="center" android:gravity="center"
android:paddingBottom="6dp" android:paddingBottom="6dp"
android:paddingTop="6dp" android:paddingTop="6dp"
android:text="@string/controls_add_to_playlist_title" android:text="@string/controls_add_to_playlist_title"
android:textSize="12sp"/> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/detail_controls_background" android:id="@+id/detail_controls_background"
@ -354,14 +354,14 @@
android:layout_weight="1" android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:contentDescription="@string/play_audio" android:contentDescription="@string/play_audio"
android:drawableTop="?attr/audio" android:drawableTop="?attr/audio"
android:focusable="true"
android:gravity="center" android:gravity="center"
android:paddingBottom="6dp" android:paddingBottom="6dp"
android:paddingTop="6dp" android:paddingTop="6dp"
android:text="@string/controls_background_title" android:text="@string/controls_background_title"
android:textSize="12sp"/> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/detail_controls_popup" android:id="@+id/detail_controls_popup"
@ -371,14 +371,14 @@
android:layout_weight="1" android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:contentDescription="@string/open_in_popup_mode" android:contentDescription="@string/open_in_popup_mode"
android:drawableTop="?attr/popup" android:drawableTop="?attr/popup"
android:focusable="true"
android:gravity="center" android:gravity="center"
android:paddingBottom="6dp" android:paddingBottom="6dp"
android:paddingTop="6dp" android:paddingTop="6dp"
android:text="@string/controls_popup_title" android:text="@string/controls_popup_title"
android:textSize="12sp"/> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/detail_controls_download" android:id="@+id/detail_controls_download"
@ -388,14 +388,14 @@
android:layout_weight="1" android:layout_weight="1"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:contentDescription="@string/controls_download_desc" android:contentDescription="@string/controls_download_desc"
android:drawableTop="?attr/download" android:drawableTop="?attr/download"
android:focusable="true"
android:gravity="center" android:gravity="center"
android:paddingBottom="6dp" android:paddingBottom="6dp"
android:paddingTop="6dp" android:paddingTop="6dp"
android:text="@string/download" android:text="@string/download"
android:textSize="12sp"/> android:textSize="12sp" />
</LinearLayout> </LinearLayout>
@ -404,7 +404,7 @@
android:layout_height="1px" android:layout_height="1px"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:background="?attr/separator_color"/> android:background="?attr/separator_color" />
<!--DESCRIPTIONS--> <!--DESCRIPTIONS-->
<LinearLayout <LinearLayout
@ -425,7 +425,7 @@
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/video_item_detail_upload_date_text_size" android:textSize="@dimen/video_item_detail_upload_date_text_size"
android:textStyle="bold" android:textStyle="bold"
tools:text="Published on Oct 2, 2009"/> tools:text="Published on Oct 2, 2009" />
<TextView <TextView
android:id="@+id/detail_description_view" android:id="@+id/detail_description_view"
@ -438,14 +438,64 @@
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="true" android:textIsSelectable="true"
android:textSize="@dimen/video_item_detail_description_text_size" 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 <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1px" android:layout_height="1px"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:background="?attr/separator_color"/> android:background="?attr/separator_color" />
</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/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"
tools:ignore="ContentDescription" />
</LinearLayout> </LinearLayout>
@ -467,7 +517,7 @@
android:textAllCaps="true" android:textAllCaps="true"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="@dimen/video_item_detail_next_text_size" android:textSize="@dimen/video_item_detail_next_text_size"
tools:ignore="RtlHardcoded"/> tools:ignore="RtlHardcoded" />
<LinearLayout <LinearLayout
android:id="@+id/detail_related_streams_view" android:id="@+id/detail_related_streams_view"
@ -475,7 +525,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:orientation="vertical" android:orientation="vertical"
tools:minHeight="50dp"/> tools:minHeight="50dp" />
<ImageButton <ImageButton
android:id="@+id/detail_related_streams_expand" android:id="@+id/detail_related_streams_expand"
@ -487,8 +537,12 @@
android:src="?attr/expand" android:src="?attr/expand"
android:textAlignment="center" android:textAlignment="center"
android:textAllCaps="true" android:textAllCaps="true"
tools:ignore="ContentDescription"/> tools:ignore="ContentDescription" />
</LinearLayout> </LinearLayout>
</FrameLayout>
</LinearLayout>
</TabHost>
</LinearLayout> </LinearLayout>
</RelativeLayout> </RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,112 @@
<?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" />
<!--TextView
android:id="@+id/itemAdditionalDetails"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_toEndOf="@+id/itemThumbnailView"
android:layout_toRightOf="@+id/itemThumbnailView"
android:lines="1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_upload_date_text_size"
tools:text="10M subscribers • 1000 videos" /-->
<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: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="12M" />
<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" />
</RelativeLayout>

View File

@ -0,0 +1,112 @@
<?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/itemTitleView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginBottom="2dp"
android:layout_marginTop="3dp"
android:layout_toRightOf="@+id/itemThumbnailView"
android:ellipsize="end"
android:lines="1"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/video_item_search_title_text_size"
tools:ignore="RtlHardcoded"
tools:text="Channel Title, Lorem ipsum"/-->
<TextView
android:id="@+id/itemCommentContentView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
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" />
<!--TextView
android:id="@+id/itemAdditionalDetails"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/itemTitleView"
android:layout_toRightOf="@+id/itemThumbnailView"
android:lines="1"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="@dimen/video_item_search_upload_date_text_size"
tools:ignore="RtlHardcoded"
tools:text="10M subscribers"/-->
<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: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="12M" />
<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" />
</RelativeLayout>

View File

@ -135,6 +135,7 @@
<string name="show_search_suggestions_key" translatable="false">show_search_suggestions</string> <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_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_next_video_key" translatable="false">show_next_video</string>
<string name="show_comments" translatable="false">show_comments</string>
<string name="show_hold_to_append_key" translatable="false">show_hold_to_append</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_language_value">en</string>
<string name="default_country_value">GB</string> <string name="default_country_value">GB</string>

View File

@ -129,6 +129,7 @@
<string name="playlist">Playlist</string> <string name="playlist">Playlist</string>
<string name="playlists">Playlists</string> <string name="playlists">Playlists</string>
<string name="videos">Videos</string> <string name="videos">Videos</string>
<string name="comments">Comments</string>
<string name="tracks">Tracks</string> <string name="tracks">Tracks</string>
<string name="users">Users</string> <string name="users">Users</string>
<string name="yes">Yes</string> <string name="yes">Yes</string>