mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 15:23:00 +00:00 
			
		
		
		
	feat: prettier channel info page
This commit is contained in:
		| @@ -276,7 +276,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo> { | ||||
|                 final String description = currentInfo.getDescription(); | ||||
|                 if (description != null && !description.isEmpty()) { | ||||
|                     tabAdapter.addFragment( | ||||
|                             ChannelInfoFragment.getInstance(description), "Info"); | ||||
|                             ChannelInfoFragment.getInstance(currentInfo), "Info"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1,22 +1,47 @@ | ||||
| package org.schabi.newpipe.fragments.list.channel; | ||||
|  | ||||
| import static org.schabi.newpipe.extractor.stream.StreamExtractor.UNKNOWN_SUBSCRIBER_COUNT; | ||||
| import static org.schabi.newpipe.extractor.utils.Utils.isBlank; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.LinearLayout; | ||||
|  | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.annotation.StringRes; | ||||
|  | ||||
| import com.google.android.material.chip.Chip; | ||||
|  | ||||
| import org.schabi.newpipe.BaseFragment; | ||||
| import org.schabi.newpipe.R; | ||||
| import org.schabi.newpipe.databinding.FragmentChannelInfoBinding; | ||||
| import org.schabi.newpipe.databinding.ItemMetadataBinding; | ||||
| import org.schabi.newpipe.databinding.ItemMetadataTagsBinding; | ||||
| import org.schabi.newpipe.extractor.channel.ChannelInfo; | ||||
| 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.external_communication.TextLinkifier; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| import icepick.State; | ||||
| import io.reactivex.rxjava3.disposables.CompositeDisposable; | ||||
|  | ||||
| public class ChannelInfoFragment extends BaseFragment { | ||||
|     private String description; | ||||
|     @State | ||||
|     protected ChannelInfo channelInfo; | ||||
|  | ||||
|     public static ChannelInfoFragment getInstance(final String description) { | ||||
|     private final CompositeDisposable disposables = new CompositeDisposable(); | ||||
|     private FragmentChannelInfoBinding binding; | ||||
|  | ||||
|     public static ChannelInfoFragment getInstance(final ChannelInfo channelInfo) { | ||||
|         final ChannelInfoFragment fragment = new ChannelInfoFragment(); | ||||
|         fragment.description = description; | ||||
|         fragment.channelInfo = channelInfo; | ||||
|         return fragment; | ||||
|     } | ||||
|  | ||||
| @@ -28,11 +53,92 @@ public class ChannelInfoFragment extends BaseFragment { | ||||
|     public View onCreateView(@NonNull final LayoutInflater inflater, | ||||
|                              @Nullable final ViewGroup container, | ||||
|                              final Bundle savedInstanceState) { | ||||
|         final FragmentChannelInfoBinding binding = | ||||
|                 FragmentChannelInfoBinding.inflate(inflater, container, false); | ||||
|         binding.descriptionText.setText(description); | ||||
|  | ||||
|         binding = FragmentChannelInfoBinding.inflate(inflater, container, false); | ||||
|         loadDescription(); | ||||
|         setupMetadata(inflater, binding.detailMetadataLayout); | ||||
|         return binding.getRoot(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         disposables.clear(); | ||||
|     } | ||||
|  | ||||
|     private void loadDescription() { | ||||
|         final String description = channelInfo.getDescription(); | ||||
|  | ||||
|         if (description == null || description.isEmpty()) { | ||||
|             binding.descriptionTitle.setVisibility(View.GONE); | ||||
|             binding.descriptionView.setVisibility(View.GONE); | ||||
|         } else { | ||||
|             TextLinkifier.createLinksFromPlainText( | ||||
|                     binding.descriptionView, description, null, disposables); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void setupMetadata(final LayoutInflater inflater, | ||||
|                                final LinearLayout layout) { | ||||
|         Context context = getActivity(); | ||||
|  | ||||
|         if (channelInfo.getSubscriberCount() != UNKNOWN_SUBSCRIBER_COUNT) { | ||||
|             addMetadataItem(inflater, layout, R.string.metadata_subscribers, | ||||
|                     Localization.localizeNumber(context, channelInfo.getSubscriberCount())); | ||||
|         } | ||||
|  | ||||
|         addTagsMetadataItem(inflater, layout); | ||||
|     } | ||||
|  | ||||
|     private void addMetadataItem(final LayoutInflater inflater, | ||||
|                                  final LinearLayout layout, | ||||
|                                  @StringRes final int type, | ||||
|                                  @Nullable final String content) { | ||||
|         if (isBlank(content)) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         final ItemMetadataBinding itemBinding = | ||||
|                 ItemMetadataBinding.inflate(inflater, layout, false); | ||||
|  | ||||
|         itemBinding.metadataTypeView.setText(type); | ||||
|         itemBinding.metadataTypeView.setOnLongClickListener(v -> { | ||||
|             ShareUtils.copyToClipboard(requireContext(), content); | ||||
|             return true; | ||||
|         }); | ||||
|  | ||||
|         itemBinding.metadataContentView.setText(content); | ||||
|  | ||||
|         layout.addView(itemBinding.getRoot()); | ||||
|     } | ||||
|  | ||||
|     private void addTagsMetadataItem(final LayoutInflater inflater, final LinearLayout layout) { | ||||
|         final List<String> tags = channelInfo.getTags(); | ||||
|  | ||||
|         if (!tags.isEmpty()) { | ||||
|             final var itemBinding = ItemMetadataTagsBinding.inflate(inflater, layout, false); | ||||
|  | ||||
|             tags.stream().sorted(String.CASE_INSENSITIVE_ORDER).forEach(tag -> { | ||||
|                 final Chip chip = (Chip) inflater.inflate(R.layout.chip, | ||||
|                         itemBinding.metadataTagsChips, false); | ||||
|                 chip.setText(tag); | ||||
|                 chip.setOnClickListener(this::onTagClick); | ||||
|                 chip.setOnLongClickListener(this::onTagLongClick); | ||||
|                 itemBinding.metadataTagsChips.addView(chip); | ||||
|             }); | ||||
|  | ||||
|             layout.addView(itemBinding.getRoot()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void onTagClick(final View chip) { | ||||
|         if (getParentFragment() != null) { | ||||
|             NavigationHelper.openSearchFragment(getParentFragment().getParentFragmentManager(), | ||||
|                     channelInfo.getServiceId(), ((Chip) chip).getText().toString()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private boolean onTagLongClick(final View chip) { | ||||
|         ShareUtils.copyToClipboard(requireContext(), ((Chip) chip).getText().toString()); | ||||
|         return true; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,8 +2,6 @@ package org.schabi.newpipe.fragments.list.channel; | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,19 @@ | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent"> | ||||
|  | ||||
|     <TextView | ||||
|         android:id="@+id/description_title" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginTop="8dp" | ||||
|         android:gravity="center" | ||||
|         android:text="@string/description_tab_description" | ||||
|         android:textAllCaps="true" | ||||
|         android:textColor="?android:attr/textColorPrimary" | ||||
|         android:textStyle="bold" | ||||
|         app:layout_constraintTop_toTopOf="parent" /> | ||||
|  | ||||
|     <!-- | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:id="@+id/description_title" | ||||
|         android:layout_width="match_parent" | ||||
| @@ -17,20 +30,45 @@ | ||||
|         android:textStyle="bold" | ||||
|         app:layout_constraintTop_toTopOf="parent" | ||||
|         tools:layout_editor_absoluteX="16dp" | ||||
|         tools:visibility="visible" /> | ||||
|         tools:visibility="visible" />--> | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:id="@+id/description_text" | ||||
|     <!--<org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:id="@+id/stats_title" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginTop="6dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:text="Stats" | ||||
|         android:textSize="16sp" | ||||
|         android:textStyle="bold" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/description_view" | ||||
|         tools:layout_editor_absoluteX="47dp" | ||||
|         tools:visibility="visible" />--> | ||||
|  | ||||
|     <org.schabi.newpipe.views.NewPipeTextView | ||||
|         android:id="@+id/description_view" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="8dp" | ||||
|         android:layout_marginEnd="8dp" | ||||
|         android:textIsSelectable="true" | ||||
|         android:textSize="14sp" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/description_title" | ||||
|         tools:layout_editor_absoluteX="36dp" | ||||
|         tools:visibility="visible" | ||||
|         tools:text="Cupcake ipsum dolor sit amet I love. I love macaroon cake sweet topping jelly beans chocolate chupa chups candy canes. Marshmallow cake jelly fruitcake soufflé pie. Jelly jelly beans cupcake topping chocolate bar jelly pudding pastry sweet roll." /> | ||||
|         tools:layout_editor_absoluteX="0dp" | ||||
|         tools:text="Cupcake ipsum dolor sit amet I love. I love macaroon cake sweet topping jelly beans chocolate chupa chups candy canes. Marshmallow cake jelly fruitcake soufflé pie. Jelly jelly beans cupcake topping chocolate bar jelly pudding pastry sweet roll." | ||||
|         tools:visibility="visible" /> | ||||
|  | ||||
|     <LinearLayout | ||||
|         android:id="@+id/detail_metadata_layout" | ||||
|         android:layout_width="0dp" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:layout_marginStart="16dp" | ||||
|         android:layout_marginEnd="16dp" | ||||
|         android:layout_marginBottom="10dp" | ||||
|         android:orientation="vertical" | ||||
|         app:layout_constraintEnd_toEndOf="parent" | ||||
|         app:layout_constraintStart_toStartOf="parent" | ||||
|         app:layout_constraintTop_toBottomOf="@+id/description_view" /> | ||||
|  | ||||
| </androidx.constraintlayout.widget.ConstraintLayout> | ||||
| @@ -620,6 +620,7 @@ | ||||
|     <string name="metadata_thumbnail_url">Vorschaubild-URL</string> | ||||
|     <string name="metadata_host">Server</string> | ||||
|     <string name="metadata_support">Unterstützung</string> | ||||
|     <string name="metadata_subscribers">Abonnenten</string> | ||||
|     <string name="description_select_disable">Auswählen von Text in der Beschreibung deaktivieren</string> | ||||
|     <string name="description_select_enable">Auswählen von Text in der Beschreibung aktivieren</string> | ||||
|     <string name="description_select_note">Du kannst nun Text innerhalb der Beschreibung auswählen. Beachte, dass die Seite flackern kann und Links im Auswahlmodus möglicherweise nicht anklickbar sind.</string> | ||||
|   | ||||
| @@ -758,6 +758,7 @@ | ||||
|     <string name="metadata_privacy_unlisted">Unlisted</string> | ||||
|     <string name="metadata_privacy_private">Private</string> | ||||
|     <string name="metadata_privacy_internal">Internal</string> | ||||
|     <string name="metadata_subscribers">Subscribers</string> | ||||
|     <string name="detail_pinned_comment_view_description">Pinned comment</string> | ||||
|     <string name="detail_heart_img_view_description">Hearted by creator</string> | ||||
|     <string name="open_website_license">Open website</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ThetaDev
					ThetaDev