diff --git a/app/src/main/java/org/schabi/newpipe/BaseFragment.java b/app/src/main/java/org/schabi/newpipe/BaseFragment.java index 54513a0af..0d2412778 100644 --- a/app/src/main/java/org/schabi/newpipe/BaseFragment.java +++ b/app/src/main/java/org/schabi/newpipe/BaseFragment.java @@ -35,7 +35,7 @@ public abstract class BaseFragment extends Fragment { //////////////////////////////////////////////////////////////////////////*/ @Override - public void onAttach(final Context context) { + public void onAttach(@NonNull final Context context) { super.onAttach(context); activity = (AppCompatActivity) context; } @@ -61,7 +61,7 @@ public abstract class BaseFragment extends Fragment { @Override - public void onViewCreated(final View rootView, final Bundle savedInstanceState) { + public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); if (DEBUG) { Log.d(TAG, "onViewCreated() called with: " @@ -73,7 +73,7 @@ public abstract class BaseFragment extends Fragment { } @Override - public void onSaveInstanceState(final Bundle outState) { + public void onSaveInstanceState(@NonNull final Bundle outState) { super.onSaveInstanceState(outState); Icepick.saveInstanceState(this, outState); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java index 88f9b78b8..f876b767c 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/BaseStateFragment.java @@ -10,6 +10,7 @@ import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; @@ -56,7 +57,7 @@ public abstract class BaseStateFragment extends BaseFragment implements ViewC private TextView errorTextView; @Override - public void onViewCreated(final View rootView, final Bundle savedInstanceState) { + public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); doInitialLoadLogic(); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java new file mode 100644 index 000000000..b4424928f --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java @@ -0,0 +1,93 @@ +package org.schabi.newpipe.fragments.detail; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.text.HtmlCompat; + +import org.schabi.newpipe.BaseFragment; +import org.schabi.newpipe.databinding.FragmentDescriptionBinding; +import org.schabi.newpipe.extractor.stream.Description; +import org.schabi.newpipe.extractor.stream.StreamInfo; +import org.schabi.newpipe.util.Localization; +import org.schabi.newpipe.util.TextLinkifier; + +import icepick.State; +import io.reactivex.rxjava3.disposables.Disposable; + +import static android.text.TextUtils.isEmpty; + +public class DescriptionFragment extends BaseFragment { + + @State + StreamInfo streamInfo = null; + @Nullable + Disposable descriptionDisposable = null; + + public DescriptionFragment() { + } + + public DescriptionFragment(final StreamInfo streamInfo) { + this.streamInfo = streamInfo; + } + + @Override + public View onCreateView(@NonNull final LayoutInflater inflater, + @Nullable final ViewGroup container, + @Nullable final Bundle savedInstanceState) { + final FragmentDescriptionBinding binding = + FragmentDescriptionBinding.inflate(inflater, container, false); + if (streamInfo != null) { + setupUploadDate(binding.detailUploadDateView); + setupDescription(binding.detailDescriptionView); + } + return binding.getRoot(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (descriptionDisposable != null) { + descriptionDisposable.dispose(); + } + } + + private void setupUploadDate(final TextView uploadDateTextView) { + if (streamInfo.getUploadDate() != null) { + uploadDateTextView.setText(Localization + .localizeUploadDate(activity, streamInfo.getUploadDate().offsetDateTime())); + } else { + uploadDateTextView.setVisibility(View.GONE); + } + } + + private void setupDescription(final TextView descriptionTextView) { + final Description description = streamInfo.getDescription(); + if (description == null || isEmpty(description.getContent()) + || description == Description.emptyDescription) { + descriptionTextView.setText(""); + return; + } + + switch (description.getType()) { + case Description.HTML: + descriptionDisposable = TextLinkifier.createLinksFromHtmlBlock(requireContext(), + description.getContent(), descriptionTextView, + HtmlCompat.FROM_HTML_MODE_LEGACY); + break; + case Description.MARKDOWN: + descriptionDisposable = TextLinkifier.createLinksFromMarkdownText(requireContext(), + description.getContent(), descriptionTextView); + break; + case Description.PLAIN_TEXT: default: + descriptionDisposable = TextLinkifier.createLinksFromPlainText(requireContext(), + description.getContent(), descriptionTextView); + break; + } + } +} 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 7add95a6c..8148fb40c 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 @@ -38,7 +38,6 @@ import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.widget.Toolbar; import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.core.content.ContextCompat; -import androidx.core.text.HtmlCompat; import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; @@ -61,14 +60,12 @@ import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; import org.schabi.newpipe.extractor.stream.AudioStream; -import org.schabi.newpipe.extractor.stream.Description; import org.schabi.newpipe.extractor.stream.Stream; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.BaseStateFragment; -import org.schabi.newpipe.fragments.EmptyFragment; import org.schabi.newpipe.fragments.list.comments.CommentsFragment; import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment; import org.schabi.newpipe.ktx.AnimationType; @@ -97,9 +94,7 @@ import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.ShareUtils; -import org.schabi.newpipe.util.TextLinkifier; import org.schabi.newpipe.util.ThemeHelper; -import org.schabi.newpipe.views.LargeTextMovementMethod; import java.util.Iterator; import java.util.LinkedList; @@ -150,7 +145,7 @@ public final class VideoDetailFragment private static final String COMMENTS_TAB_TAG = "COMMENTS"; private static final String RELATED_TAB_TAG = "NEXT VIDEO"; - private static final String EMPTY_TAB_TAG = "EMPTY TAB"; + private static final String DESCRIPTION_TAB_TAG = "DESCRIPTION TAB"; private boolean showRelatedStreams; private boolean showComments; @@ -570,21 +565,16 @@ public final class VideoDetailFragment } private void toggleTitleAndDescription() { - if (binding.detailDescriptionRootLayout.getVisibility() == View.VISIBLE) { - binding.detailVideoTitleView.setMaxLines(1); - binding.detailDescriptionRootLayout.setVisibility(View.GONE); - binding.detailDescriptionView.setFocusable(false); - binding.detailToggleDescriptionView.setImageResource( - ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more)); - binding.detailSecondaryControlPanel.setVisibility(View.GONE); - } else { + if (binding.detailSecondaryControlPanel.getVisibility() == View.GONE) { binding.detailVideoTitleView.setMaxLines(10); - binding.detailDescriptionRootLayout.setVisibility(View.VISIBLE); - binding.detailDescriptionView.setFocusable(true); - binding.detailDescriptionView.setMovementMethod(new LargeTextMovementMethod()); binding.detailToggleDescriptionView.setImageResource( ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_less)); binding.detailSecondaryControlPanel.setVisibility(View.VISIBLE); + } else { + binding.detailVideoTitleView.setMaxLines(1); + binding.detailToggleDescriptionView.setImageResource( + ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more)); + binding.detailSecondaryControlPanel.setVisibility(View.GONE); } } @@ -928,10 +918,8 @@ public final class VideoDetailFragment pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); } - if (pageAdapter.getCount() == 0) { - pageAdapter.addFragment(new EmptyFragment(), EMPTY_TAB_TAG); - } - + //temp empty fragment. will be updated in handleResult + pageAdapter.addFragment(new Fragment(), DESCRIPTION_TAB_TAG); pageAdapter.notifyDataSetUpdate(); if (pageAdapter.getCount() < 2) { @@ -1153,29 +1141,6 @@ public final class VideoDetailFragment binding.playerPlaceholder.requestLayout(); } - private void prepareDescription(final Description description) { - if (description == null || isEmpty(description.getContent()) - || description == Description.emptyDescription) { - return; - } - - switch (description.getType()) { - case Description.HTML: - disposables.add(TextLinkifier.createLinksFromHtmlBlock(requireContext(), - description.getContent(), binding.detailDescriptionView, - HtmlCompat.FROM_HTML_MODE_LEGACY)); - break; - case Description.MARKDOWN: - disposables.add(TextLinkifier.createLinksFromMarkdownText(requireContext(), - description.getContent(), binding.detailDescriptionView)); - break; - case Description.PLAIN_TEXT: default: - disposables.add(TextLinkifier.createLinksFromPlainText(requireContext(), - description.getContent(), binding.detailDescriptionView)); - break; - } - } - private final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() { @Override @@ -1348,7 +1313,6 @@ public final class VideoDetailFragment binding.detailVideoTitleView.setMaxLines(1); animate(binding.detailVideoTitleView, true, 0); - binding.detailDescriptionRootLayout.setVisibility(View.GONE); binding.detailToggleDescriptionView.setVisibility(View.GONE); binding.detailTitleRootLayout.setClickable(false); binding.detailSecondaryControlPanel.setVisibility(View.GONE); @@ -1379,7 +1343,6 @@ public final class VideoDetailFragment if (binding.relatedStreamsLayout == null) { //phone pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(info)); - pageAdapter.notifyDataSetUpdate(); } else { //tablet getChildFragmentManager().beginTransaction() .replace(R.id.relatedStreamsLayout, @@ -1389,6 +1352,10 @@ public final class VideoDetailFragment player != null && player.isFullscreen() ? View.GONE : View.VISIBLE); } } + pageAdapter.updateItem(DESCRIPTION_TAB_TAG, + new DescriptionFragment(info)); + pageAdapter.notifyDataSetUpdate(); + animate(binding.detailThumbnailPlayButton, true, 200); binding.detailVideoTitleView.setText(title); @@ -1397,7 +1364,7 @@ public final class VideoDetailFragment } else if (!isEmpty(info.getUploaderName())) { displayUploaderAsSubChannel(info); } else { - binding.detailUploadDateView.setVisibility(View.GONE); + binding.detailUploaderTextView.setVisibility(View.GONE); binding.detailUploaderThumbnailView.setVisibility(View.GONE); } @@ -1465,23 +1432,12 @@ public final class VideoDetailFragment binding.detailDurationView.setVisibility(View.GONE); } - binding.detailDescriptionView.setVisibility(View.GONE); binding.detailTitleRootLayout.setClickable(true); binding.detailToggleDescriptionView.setImageResource( ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more)); binding.detailToggleDescriptionView.setVisibility(View.VISIBLE); - binding.detailDescriptionRootLayout.setVisibility(View.GONE); binding.detailSecondaryControlPanel.setVisibility(View.GONE); - if (info.getUploadDate() != null) { - binding.detailUploadDateView.setText(Localization - .localizeUploadDate(activity, info.getUploadDate().offsetDateTime())); - binding.detailUploadDateView.setVisibility(View.VISIBLE); - } else { - binding.detailUploadDateView.setText(null); - binding.detailUploadDateView.setVisibility(View.GONE); - } - sortedVideoStreams = ListHelper.getSortedStreamVideosList( activity, info.getVideoStreams(), @@ -1489,7 +1445,6 @@ public final class VideoDetailFragment false); selectedVideoStreamIndex = ListHelper .getDefaultResolutionIndex(activity, sortedVideoStreams); - prepareDescription(info.getDescription()); updateProgressInfo(info); initThumbnailViews(info); disposables.add(showMetaInfoInTextView(info.getMetaInfo(), binding.detailMetaInfoTextView, @@ -1535,7 +1490,7 @@ public final class VideoDetailFragment binding.detailSubChannelTextView.setText(info.getUploaderName()); binding.detailSubChannelTextView.setVisibility(View.VISIBLE); binding.detailSubChannelTextView.setSelected(true); - binding.detailUploadDateView.setVisibility(View.GONE); + binding.detailUploaderTextView.setVisibility(View.GONE); } private void displayBothUploaderAndSubChannel(final StreamInfo info) { @@ -1546,12 +1501,12 @@ public final class VideoDetailFragment binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE); if (!isEmpty(info.getUploaderName())) { - binding.detailUploadDateView.setText( + binding.detailUploaderTextView.setText( String.format(getString(R.string.video_detail_by), info.getUploaderName())); - binding.detailUploadDateView.setVisibility(View.VISIBLE); - binding.detailUploadDateView.setSelected(true); + binding.detailUploaderTextView.setVisibility(View.VISIBLE); + binding.detailUploaderTextView.setSelected(true); } else { - binding.detailUploadDateView.setVisibility(View.GONE); + binding.detailUploaderTextView.setVisibility(View.GONE); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java index b251d4b93..d42b0a088 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/BaseListFragment.java @@ -70,7 +70,7 @@ public abstract class BaseListFragment extends BaseStateFragment //////////////////////////////////////////////////////////////////////////*/ @Override - public void onAttach(final Context context) { + public void onAttach(@NonNull final Context context) { super.onAttach(context); if (infoListAdapter == null) { @@ -186,7 +186,7 @@ public abstract class BaseListFragment extends BaseStateFragment } @Override - public void onSaveInstanceState(final Bundle bundle) { + public void onSaveInstanceState(@NonNull final Bundle bundle) { super.onSaveInstanceState(bundle); if (useDefaultStateSaving) { savedState = StateSaver diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index b4dd45e93..e8a5d380b 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -106,7 +106,7 @@ public class ChannelFragment extends BaseListInfoFragment //////////////////////////////////////////////////////////////////////////*/ @Override - public void onAttach(final Context context) { + public void onAttach(@NonNull final Context context) { super.onAttach(context); subscriptionManager = new SubscriptionManager(activity); } @@ -119,7 +119,7 @@ public class ChannelFragment extends BaseListInfoFragment } @Override - public void onViewCreated(final View rootView, final Bundle savedInstanceState) { + public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) { super.onViewCreated(rootView, savedInstanceState); channelBinding = FragmentChannelBinding.bind(rootView); } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java index c0abc469b..3682fe13b 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/comments/CommentsFragment.java @@ -1,6 +1,5 @@ package org.schabi.newpipe.fragments.list.comments; -import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.Menu; @@ -37,11 +36,6 @@ public class CommentsFragment extends BaseListInfoFragment { // LifeCycle //////////////////////////////////////////////////////////////////////////*/ - @Override - public void onAttach(final Context context) { - super.onAttach(context); - } - @Override public View onCreateView(@NonNull final LayoutInflater inflater, @Nullable final ViewGroup container, @@ -52,9 +46,7 @@ public class CommentsFragment extends BaseListInfoFragment { @Override public void onDestroy() { super.onDestroy(); - if (disposables != null) { - disposables.clear(); - } + disposables.clear(); } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java index b15bb97f2..5273fd396 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/search/SearchFragment.java @@ -196,7 +196,7 @@ public class SearchFragment extends BaseListFragment @@ -588,53 +589,6 @@ android:layout_marginRight="8dp" android:background="?attr/separator_color" /> - - - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_description.xml b/app/src/main/res/layout/fragment_description.xml new file mode 100644 index 000000000..e3845e892 --- /dev/null +++ b/app/src/main/res/layout/fragment_description.xml @@ -0,0 +1,48 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_video_detail.xml b/app/src/main/res/layout/fragment_video_detail.xml index 612ec389a..7beb41ee3 100644 --- a/app/src/main/res/layout/fragment_video_detail.xml +++ b/app/src/main/res/layout/fragment_video_detail.xml @@ -493,7 +493,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:padding="@dimen/detail_control_padding" + android:paddingHorizontal="@dimen/detail_control_padding" + android:paddingBottom="@dimen/detail_control_padding" android:visibility="gone" tools:visibility="visible"> @@ -571,49 +572,6 @@ android:layout_marginRight="8dp" android:background="?attr/separator_color" /> - - - - - - - - - - -