diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 11a315d69..a364c42cd 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -882,7 +882,7 @@ public final class VideoDetailFragment if (shouldShowComments()) { pageAdapter.addFragment( - CommentsFragment.getInstance(serviceId, url, title), COMMENTS_TAB_TAG); + CommentsFragment.getInstance(serviceId, url), COMMENTS_TAB_TAG); tabIcons.add(R.drawable.ic_comment); tabContentDescriptions.add(R.string.comments_tab_description); } @@ -1014,16 +1014,15 @@ public final class VideoDetailFragment public void scrollToComment(final CommentsInfoItem comment) { final int commentsTabPos = pageAdapter.getItemPositionByTitle(COMMENTS_TAB_TAG); - final Fragment fragment = pageAdapter.getItem(commentsTabPos); - if (!(fragment instanceof CommentsFragment)) { - return; - } + final var fragment = pageAdapter.getItem(commentsTabPos); + // TODO: Implement the scrolling with Compose. // unexpand the app bar only if scrolling to the comment succeeded - if (((CommentsFragment) fragment).scrollToComment(comment)) { - binding.appBarLayout.setExpanded(false, false); - binding.viewPager.setCurrentItem(commentsTabPos, false); - } +// if (fragment instanceof CommentsFragment commentsFragment && +// commentsFragment.scrollToComment(comment)) { +// binding.appBarLayout.setExpanded(false, false); +// binding.viewPager.setCurrentItem(commentsTabPos, false); +// } } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/Comment.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/Comment.kt index 36e7aebf6..ac254a5b3 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/Comment.kt +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/Comment.kt @@ -83,8 +83,7 @@ fun Comment(comment: CommentsInfoItem) { .clip(CircleShape) .clickable { NavigationHelper.openCommentAuthorIfPresent( - context as FragmentActivity, - comment + context as FragmentActivity, comment ) } ) @@ -140,7 +139,11 @@ fun Comment(comment: CommentsInfoItem) { } if (comment.replies != null) { - TextButton(onClick = { /*TODO*/ }) { + TextButton(onClick = { + NavigationHelper.openCommentRepliesFragment( + context as FragmentActivity, comment + ) + }) { Text( text = pluralStringResource( R.plurals.replies, comment.replyCount, comment.replyCount.toString() diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.kt index 4a362b8f8..e25b3a960 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesFragment.kt @@ -31,17 +31,17 @@ class CommentRepliesFragment : Fragment() { bar.setDisplayShowTitleEnabled(true) bar.title = Localization.replyCount(activity, comment.replyCount) - return ComposeView(requireContext()).apply { + return ComposeView(activity).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { val flow = remember(comment) { Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { - CommentRepliesSource(comment) + CommentsSource(comment.serviceId, comment.url, comment.replies) }.flow } AppTheme { - CommentReplies(comment = comment, flow = flow) + CommentSection(parentComment = comment, flow = flow) } } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesSource.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesSource.kt deleted file mode 100644 index ed602d917..000000000 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentRepliesSource.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.schabi.newpipe.fragments.list.comments - -import androidx.paging.PagingState -import androidx.paging.rxjava3.RxPagingSource -import io.reactivex.rxjava3.core.Single -import io.reactivex.rxjava3.schedulers.Schedulers -import org.schabi.newpipe.extractor.Page -import org.schabi.newpipe.extractor.comments.CommentsInfoItem -import org.schabi.newpipe.util.ExtractorHelper - -class CommentRepliesSource( - private val commentsInfoItem: CommentsInfoItem, -) : RxPagingSource() { - override fun loadSingle(params: LoadParams): Single> { - val nextPage = params.key ?: commentsInfoItem.replies - return ExtractorHelper.getMoreCommentItems(commentsInfoItem.serviceId, commentsInfoItem.url, nextPage) - .subscribeOn(Schedulers.io()) - .map { LoadResult.Page(it.items, null, it.nextPage) } - } - - override fun getRefreshKey(state: PagingState) = null -} diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentReplies.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentSection.kt similarity index 62% rename from app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentReplies.kt rename to app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentSection.kt index 53a4fa4bf..45a8b5e72 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentReplies.kt +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentSection.kt @@ -15,16 +15,18 @@ import org.schabi.newpipe.extractor.stream.Description import org.schabi.newpipe.ui.theme.AppTheme @Composable -fun CommentReplies( - comment: CommentsInfoItem, - flow: Flow> +fun CommentSection( + flow: Flow>, + parentComment: CommentsInfoItem? = null, ) { val replies = flow.collectAsLazyPagingItems() LazyColumn { - item { - CommentRepliesHeader(comment = comment) - HorizontalDivider(thickness = 1.dp) + if (parentComment != null) { + item { + CommentRepliesHeader(comment = parentComment) + HorizontalDivider(thickness = 1.dp) + } } items(replies.itemCount) { @@ -33,6 +35,25 @@ fun CommentReplies( } } +@Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun CommentSectionPreview() { + val comment1 = CommentsInfoItem( + commentText = Description("This is a comment", Description.PLAIN_TEXT), + uploaderName = "Test", + ) + val comment2 = CommentsInfoItem( + commentText = Description("This is another comment.
This is another line.", Description.HTML), + uploaderName = "Test 2", + ) + val flow = flowOf(PagingData.from(listOf(comment1, comment2))) + + AppTheme { + CommentSection(flow = flow) + } +} + @Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -56,6 +77,6 @@ private fun CommentRepliesPreview() { val flow = flowOf(PagingData.from(listOf(reply1, reply2))) AppTheme { - CommentReplies(comment = comment, flow = flow) + CommentSection(parentComment = comment, flow = flow) } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.kt index e25e02794..decd9391c 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.kt @@ -1,123 +1,55 @@ -package org.schabi.newpipe.fragments.list.comments; +package org.schabi.newpipe.fragments.list.comments -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.paging.Pager +import androidx.paging.PagingConfig +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.util.NO_SERVICE_ID -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; +class CommentsFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val arguments = requireArguments() + val serviceId = arguments.getInt(SERVICE_ID, NO_SERVICE_ID) + val url = arguments.getString(URL) -import org.schabi.newpipe.R; -import org.schabi.newpipe.error.UserAction; -import org.schabi.newpipe.extractor.ListExtractor; -import org.schabi.newpipe.extractor.comments.CommentsInfo; -import org.schabi.newpipe.extractor.comments.CommentsInfoItem; -import org.schabi.newpipe.fragments.list.BaseListInfoFragment; -import org.schabi.newpipe.info_list.ItemViewMode; -import org.schabi.newpipe.ktx.ViewUtils; -import org.schabi.newpipe.util.ExtractorHelper; + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + val flow = remember(serviceId, url) { + Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { + CommentsSource(serviceId, url, null) + }.flow + } -import io.reactivex.rxjava3.core.Single; -import io.reactivex.rxjava3.disposables.CompositeDisposable; - -public class CommentsFragment extends BaseListInfoFragment { - private final CompositeDisposable disposables = new CompositeDisposable(); - - private TextView emptyStateDesc; - - public static CommentsFragment getInstance(final int serviceId, final String url, - final String name) { - final CommentsFragment instance = new CommentsFragment(); - instance.setInitialData(serviceId, url, name); - return instance; - } - - public CommentsFragment() { - super(UserAction.REQUESTED_COMMENTS); - } - - @Override - protected void initViews(final View rootView, final Bundle savedInstanceState) { - super.initViews(rootView, savedInstanceState); - - emptyStateDesc = rootView.findViewById(R.id.empty_state_desc); - } - - /*////////////////////////////////////////////////////////////////////////// - // LifeCycle - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public View onCreateView(@NonNull final LayoutInflater inflater, - @Nullable final ViewGroup container, - @Nullable final Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_comments, container, false); - } - - @Override - public void onDestroy() { - super.onDestroy(); - disposables.clear(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Load and handle - //////////////////////////////////////////////////////////////////////////*/ - - @Override - protected Single> loadMoreItemsLogic() { - return ExtractorHelper.getMoreCommentItems(serviceId, currentInfo, currentNextPage); - } - - @Override - protected Single loadResult(final boolean forceLoad) { - return ExtractorHelper.getCommentsInfo(serviceId, url, forceLoad); - } - - /*////////////////////////////////////////////////////////////////////////// - // Contract - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void handleResult(@NonNull final CommentsInfo result) { - super.handleResult(result); - - emptyStateDesc.setText( - result.isCommentsDisabled() - ? R.string.comments_are_disabled - : R.string.no_comments); - - ViewUtils.slideUp(requireView(), 120, 150, 0.06f); - disposables.clear(); - } - - /*////////////////////////////////////////////////////////////////////////// - // Utils - //////////////////////////////////////////////////////////////////////////*/ - - @Override - public void setTitle(final String title) { } - - @Override - public void onCreateOptionsMenu(@NonNull final Menu menu, - @NonNull final MenuInflater inflater) { } - - @Override - protected ItemViewMode getItemViewMode() { - return ItemViewMode.LIST; - } - - public boolean scrollToComment(final CommentsInfoItem comment) { - final int position = infoListAdapter.getItemsList().indexOf(comment); - if (position < 0) { - return false; + AppTheme { + CommentSection(flow = flow) + } + } } + } - itemsList.scrollToPosition(position); - return true; + companion object { + private const val SERVICE_ID = "serviceId" + private const val URL = "url" + + @JvmStatic + fun getInstance(serviceId: Int, url: String?) = CommentsFragment().apply { + arguments = bundleOf( + SERVICE_ID to serviceId, + URL to url + ) + } } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsSource.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsSource.kt new file mode 100644 index 000000000..6288efaec --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsSource.kt @@ -0,0 +1,36 @@ +package org.schabi.newpipe.fragments.list.comments + +import androidx.paging.PagingState +import androidx.paging.rxjava3.RxPagingSource +import io.reactivex.rxjava3.core.Single +import io.reactivex.rxjava3.schedulers.Schedulers +import org.schabi.newpipe.extractor.Page +import org.schabi.newpipe.extractor.comments.CommentsInfoItem +import org.schabi.newpipe.util.ExtractorHelper + +class CommentsSource( + private val serviceId: Int, + private val url: String?, + private val repliesPage: Page? +) : RxPagingSource() { + override fun loadSingle(params: LoadParams): Single> { + // repliesPage is non-null only when used to load the comment replies + val nextKey = params.key ?: repliesPage + + return nextKey?.let { + ExtractorHelper.getMoreCommentItems(serviceId, url, it) + .subscribeOn(Schedulers.io()) + .map { LoadResult.Page(it.items, null, it.nextPage) } + } ?: ExtractorHelper.getCommentsInfo(serviceId, url, false) + .subscribeOn(Schedulers.io()) + .map { + if (it.isCommentsDisabled) { + LoadResult.Invalid() + } else { + LoadResult.Page(it.relatedItems, null, it.nextPage) + } + } + } + + override fun getRefreshKey(state: PagingState) = null +} diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java index d959c6327..a1526af28 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java @@ -13,7 +13,6 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem; import org.schabi.newpipe.extractor.stream.StreamInfoItem; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder; -import org.schabi.newpipe.info_list.holder.CommentInfoItemHolder; import org.schabi.newpipe.info_list.holder.InfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder; @@ -75,21 +74,16 @@ public class InfoItemBuilder { private InfoItemHolder holderFromInfoType(@NonNull final ViewGroup parent, @NonNull final InfoItem.InfoType infoType, final boolean useMiniVariant) { - switch (infoType) { - case STREAM: - return useMiniVariant ? new StreamMiniInfoItemHolder(this, parent) - : new StreamInfoItemHolder(this, parent); - case CHANNEL: - return useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) - : new ChannelInfoItemHolder(this, parent); - case PLAYLIST: - return useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) - : new PlaylistInfoItemHolder(this, parent); - case COMMENT: - return new CommentInfoItemHolder(this, parent); - default: - throw new RuntimeException("InfoType not expected = " + infoType.name()); - } + return switch (infoType) { + case STREAM -> useMiniVariant ? new StreamMiniInfoItemHolder(this, parent) + : new StreamInfoItemHolder(this, parent); + case CHANNEL -> useMiniVariant ? new ChannelMiniInfoItemHolder(this, parent) + : new ChannelInfoItemHolder(this, parent); + case PLAYLIST -> useMiniVariant ? new PlaylistMiniInfoItemHolder(this, parent) + : new PlaylistInfoItemHolder(this, parent); + case COMMENT -> + throw new IllegalArgumentException("Comments should be rendered using Compose"); + }; } public Context getContext() { diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java index 575568c00..e7cf9ba9a 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java @@ -21,7 +21,6 @@ import org.schabi.newpipe.info_list.holder.ChannelCardInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder; import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder; -import org.schabi.newpipe.info_list.holder.CommentInfoItemHolder; import org.schabi.newpipe.info_list.holder.InfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistCardInfoItemHolder; import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder; @@ -283,46 +282,32 @@ public class InfoListAdapter extends RecyclerView.Adapter new HFHolder(headerSupplier.get()); + case FOOTER_TYPE -> new HFHolder(PignateFooterBinding + .inflate(layoutInflater, parent, false) + .getRoot() + ); + case MINI_STREAM_HOLDER_TYPE -> new StreamMiniInfoItemHolder(infoItemBuilder, parent); + case STREAM_HOLDER_TYPE -> new StreamInfoItemHolder(infoItemBuilder, parent); + case GRID_STREAM_HOLDER_TYPE -> new StreamGridInfoItemHolder(infoItemBuilder, parent); + case CARD_STREAM_HOLDER_TYPE -> new StreamCardInfoItemHolder(infoItemBuilder, parent); + case MINI_CHANNEL_HOLDER_TYPE -> new ChannelMiniInfoItemHolder(infoItemBuilder, parent); + case CHANNEL_HOLDER_TYPE -> new ChannelInfoItemHolder(infoItemBuilder, parent); + case CARD_CHANNEL_HOLDER_TYPE -> new ChannelCardInfoItemHolder(infoItemBuilder, parent); + case GRID_CHANNEL_HOLDER_TYPE -> new ChannelGridInfoItemHolder(infoItemBuilder, parent); + case MINI_PLAYLIST_HOLDER_TYPE -> + new PlaylistMiniInfoItemHolder(infoItemBuilder, parent); + case PLAYLIST_HOLDER_TYPE -> new PlaylistInfoItemHolder(infoItemBuilder, parent); + case GRID_PLAYLIST_HOLDER_TYPE -> + new PlaylistGridInfoItemHolder(infoItemBuilder, parent); + case CARD_PLAYLIST_HOLDER_TYPE -> + new PlaylistCardInfoItemHolder(infoItemBuilder, parent); + default -> new FallbackViewHolder(new View(parent.getContext())); + }; } @Override diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java deleted file mode 100644 index a3316d3fe..000000000 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentInfoItemHolder.java +++ /dev/null @@ -1,208 +0,0 @@ -package org.schabi.newpipe.info_list.holder; - -import static org.schabi.newpipe.util.ServiceHelper.getServiceById; -import static org.schabi.newpipe.util.text.TouchUtils.getOffsetForHorizontalLine; - -import android.text.Spanned; -import android.text.method.LinkMovementMethod; -import android.text.style.ClickableSpan; -import android.text.style.URLSpan; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.fragment.app.FragmentActivity; - -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.local.history.HistoryRecordManager; -import org.schabi.newpipe.util.DeviceUtils; -import org.schabi.newpipe.util.Localization; -import org.schabi.newpipe.util.NavigationHelper; -import org.schabi.newpipe.util.external_communication.ShareUtils; -import org.schabi.newpipe.util.image.CoilHelper; -import org.schabi.newpipe.util.image.ImageStrategy; -import org.schabi.newpipe.util.text.TextEllipsizer; - -public class CommentInfoItemHolder extends InfoItemHolder { - - private static final int COMMENT_DEFAULT_LINES = 2; - private final int commentHorizontalPadding; - private final int commentVerticalPadding; - - private final RelativeLayout itemRoot; - private final ImageView itemThumbnailView; - private final TextView itemContentView; - private final ImageView itemThumbsUpView; - private final TextView itemLikesCountView; - private final TextView itemTitleView; - private final ImageView itemHeartView; - private final ImageView itemPinnedView; - private final Button repliesButton; - - @NonNull - private final TextEllipsizer textEllipsizer; - - public CommentInfoItemHolder(final InfoItemBuilder infoItemBuilder, - final ViewGroup parent) { - super(infoItemBuilder, R.layout.list_comment_item, parent); - - itemRoot = itemView.findViewById(R.id.itemRoot); - itemThumbnailView = itemView.findViewById(R.id.itemThumbnailView); - itemContentView = itemView.findViewById(R.id.itemCommentContentView); - itemThumbsUpView = itemView.findViewById(R.id.detail_thumbs_up_img_view); - itemLikesCountView = itemView.findViewById(R.id.detail_thumbs_up_count_view); - itemTitleView = itemView.findViewById(R.id.itemTitleView); - itemHeartView = itemView.findViewById(R.id.detail_heart_image_view); - itemPinnedView = itemView.findViewById(R.id.detail_pinned_view); - repliesButton = itemView.findViewById(R.id.replies_button); - - commentHorizontalPadding = (int) infoItemBuilder.getContext() - .getResources().getDimension(R.dimen.comments_horizontal_padding); - commentVerticalPadding = (int) infoItemBuilder.getContext() - .getResources().getDimension(R.dimen.comments_vertical_padding); - - textEllipsizer = new TextEllipsizer(itemContentView, COMMENT_DEFAULT_LINES, null); - textEllipsizer.setStateChangeListener(isEllipsized -> { - if (Boolean.TRUE.equals(isEllipsized)) { - denyLinkFocus(); - } else { - determineMovementMethod(); - } - }); - } - - @Override - public void updateFromItem(final InfoItem infoItem, - final HistoryRecordManager historyRecordManager) { - if (!(infoItem instanceof CommentsInfoItem item)) { - return; - } - - // load the author avatar - CoilHelper.INSTANCE.loadAvatar(itemThumbnailView, item.getUploaderAvatars()); - if (ImageStrategy.shouldLoadImages()) { - itemThumbnailView.setVisibility(View.VISIBLE); - itemRoot.setPadding(commentVerticalPadding, commentVerticalPadding, - commentVerticalPadding, commentVerticalPadding); - } else { - itemThumbnailView.setVisibility(View.GONE); - itemRoot.setPadding(commentHorizontalPadding, commentVerticalPadding, - commentHorizontalPadding, commentVerticalPadding); - } - itemThumbnailView.setOnClickListener(view -> openCommentAuthor(item)); - - - // setup the top row, with pinned icon, author name and comment date - itemPinnedView.setVisibility(item.isPinned() ? View.VISIBLE : View.GONE); - itemTitleView.setText(Localization.concatenateStrings(item.getUploaderName(), - Localization.relativeTimeOrTextual(itemBuilder.getContext(), item.getUploadDate(), - item.getTextualUploadDate()))); - - - // setup bottom row, with likes, heart and replies button - itemLikesCountView.setText( - Localization.likeCount(itemBuilder.getContext(), item.getLikeCount())); - - itemHeartView.setVisibility(item.isHeartedByUploader() ? View.VISIBLE : View.GONE); - - final boolean hasReplies = item.getReplies() != null; - repliesButton.setOnClickListener(hasReplies ? v -> openCommentReplies(item) : null); - repliesButton.setVisibility(hasReplies ? View.VISIBLE : View.GONE); - repliesButton.setText(hasReplies - ? Localization.replyCount(itemBuilder.getContext(), item.getReplyCount()) : ""); - ((RelativeLayout.LayoutParams) itemThumbsUpView.getLayoutParams()).topMargin = - hasReplies ? 0 : DeviceUtils.dpToPx(6, itemBuilder.getContext()); - - - // setup comment content and click listeners to expand/ellipsize it - textEllipsizer.setStreamingService(getServiceById(item.getServiceId())); - textEllipsizer.setStreamUrl(item.getUrl()); - textEllipsizer.setContent(item.getCommentText()); - textEllipsizer.ellipsize(); - - //noinspection ClickableViewAccessibility - itemContentView.setOnTouchListener((v, event) -> { - final CharSequence text = itemContentView.getText(); - if (text instanceof Spanned buffer) { - final int action = event.getAction(); - - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { - final int offset = getOffsetForHorizontalLine(itemContentView, event); - final var links = buffer.getSpans(offset, offset, ClickableSpan.class); - - if (links.length != 0) { - if (action == MotionEvent.ACTION_UP) { - links[0].onClick(itemContentView); - } - // we handle events that intersect links, so return true - return true; - } - } - } - return false; - }); - - itemView.setOnClickListener(view -> { - textEllipsizer.toggle(); - if (itemBuilder.getOnCommentsSelectedListener() != null) { - itemBuilder.getOnCommentsSelectedListener().selected(item); - } - }); - - itemView.setOnLongClickListener(view -> { - if (DeviceUtils.isTv(itemBuilder.getContext())) { - openCommentAuthor(item); - } else { - final CharSequence text = itemContentView.getText(); - if (text != null) { - ShareUtils.copyToClipboard(itemBuilder.getContext(), text.toString()); - } - } - return true; - }); - } - - private void openCommentAuthor(@NonNull final CommentsInfoItem item) { - NavigationHelper.openCommentAuthorIfPresent((FragmentActivity) itemBuilder.getContext(), - item); - } - - private void openCommentReplies(@NonNull final CommentsInfoItem item) { - NavigationHelper.openCommentRepliesFragment((FragmentActivity) itemBuilder.getContext(), - item); - } - - private void allowLinkFocus() { - itemContentView.setMovementMethod(LinkMovementMethod.getInstance()); - } - - private void denyLinkFocus() { - itemContentView.setMovementMethod(null); - } - - private boolean shouldFocusLinks() { - if (itemView.isInTouchMode()) { - return false; - } - - final URLSpan[] urls = itemContentView.getUrls(); - - return urls != null && urls.length != 0; - } - - private void determineMovementMethod() { - if (shouldFocusLinks()) { - allowLinkFocus(); - } else { - denyLinkFocus(); - } - } -} diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index 066d5f570..abf8d24c1 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -155,15 +155,6 @@ public final class ExtractorHelper { CommentsInfo.getInfo(NewPipe.getService(serviceId), url))); } - public static Single> getMoreCommentItems( - final int serviceId, - final CommentsInfo info, - final Page nextPage) { - checkServiceId(serviceId); - return Single.fromCallable(() -> - CommentsInfo.getMoreItems(NewPipe.getService(serviceId), info, nextPage)); - } - public static Single> getMoreCommentItems( final int serviceId, final String url, diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml deleted file mode 100644 index 2a8c747cd..000000000 --- a/app/src/main/res/layout/fragment_comments.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/list_comment_item.xml b/app/src/main/res/layout/list_comment_item.xml deleted file mode 100644 index 631ab204b..000000000 --- a/app/src/main/res/layout/list_comment_item.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - -