diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/AboutChannelFragment.kt b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/AboutChannelFragment.kt new file mode 100644 index 00000000000..a4c8ae3f5ce --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/AboutChannelFragment.kt @@ -0,0 +1,36 @@ +package org.schabi.newpipe.fragments.list.channel + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.core.os.bundleOf +import androidx.fragment.app.Fragment +import androidx.fragment.compose.content +import org.schabi.newpipe.extractor.channel.ChannelInfo +import org.schabi.newpipe.ktx.serializable +import org.schabi.newpipe.ui.components.channel.AboutChannelSection +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.util.KEY_INFO + +class AboutChannelFragment : Fragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ) = content { + AppTheme { + Surface(color = MaterialTheme.colorScheme.background) { + AboutChannelSection(requireArguments().serializable(KEY_INFO)!!) + } + } + } + + companion object { + @JvmStatic + fun getInstance(channelInfo: ChannelInfo) = AboutChannelFragment().apply { + arguments = bundleOf(KEY_INFO to channelInfo) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java deleted file mode 100644 index 0dc2fb65a34..00000000000 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.schabi.newpipe.fragments.list.channel; - -import static org.schabi.newpipe.extractor.stream.StreamExtractor.UNKNOWN_SUBSCRIBER_COUNT; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.LinearLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.StreamingService; -import org.schabi.newpipe.extractor.channel.ChannelInfo; -import org.schabi.newpipe.extractor.stream.Description; -import org.schabi.newpipe.fragments.detail.BaseDescriptionFragment; -import org.schabi.newpipe.util.DeviceUtils; -import org.schabi.newpipe.util.Localization; - -import java.util.List; - -import icepick.State; - -public class ChannelAboutFragment extends BaseDescriptionFragment { - @State - protected ChannelInfo channelInfo; - - ChannelAboutFragment(@NonNull final ChannelInfo channelInfo) { - this.channelInfo = channelInfo; - } - - public ChannelAboutFragment() { - // keep empty constructor for IcePick when resuming fragment from memory - } - - @Override - protected void initViews(final View rootView, final Bundle savedInstanceState) { - super.initViews(rootView, savedInstanceState); - binding.constraintLayout.setPadding(0, DeviceUtils.dpToPx(8, requireContext()), 0, 0); - } - - @Nullable - @Override - protected Description getDescription() { - return new Description(channelInfo.getDescription(), Description.PLAIN_TEXT); - } - - @NonNull - @Override - protected StreamingService getService() { - return channelInfo.getService(); - } - - @Override - protected int getServiceId() { - return channelInfo.getServiceId(); - } - - @Nullable - @Override - protected String getStreamUrl() { - return null; - } - - @NonNull - @Override - public List getTags() { - return channelInfo.getTags(); - } - - @Override - protected void setupMetadata(final LayoutInflater inflater, - final LinearLayout layout) { - // There is no upload date available for channels, so hide the relevant UI element - binding.detailUploadDateView.setVisibility(View.GONE); - - if (channelInfo == null) { - return; - } - - if (channelInfo.getSubscriberCount() != UNKNOWN_SUBSCRIBER_COUNT) { - addMetadataItem(inflater, layout, false, R.string.metadata_subscribers, - Localization.localizeNumber( - requireContext(), - channelInfo.getSubscriberCount())); - } - - addImagesMetadataItem(inflater, layout, R.string.metadata_avatars, - channelInfo.getAvatars()); - addImagesMetadataItem(inflater, layout, R.string.metadata_banners, - channelInfo.getBanners()); - } -} 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 3890e48659d..ae7c03ce214 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 @@ -481,7 +481,7 @@ private void updateTabs() { if (ChannelTabHelper.showChannelTab( context, preferences, R.string.show_channel_tabs_about)) { tabAdapter.addFragment( - new ChannelAboutFragment(currentInfo), + AboutChannelFragment.getInstance(currentInfo), context.getString(R.string.channel_tab_about)); } } diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/channel/AboutChannelSection.kt b/app/src/main/java/org/schabi/newpipe/ui/components/channel/AboutChannelSection.kt new file mode 100644 index 00000000000..8fa3ca7c568 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/ui/components/channel/AboutChannelSection.kt @@ -0,0 +1,71 @@ +package org.schabi.newpipe.ui.components.channel + +import android.content.res.Configuration +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.schabi.newpipe.R +import org.schabi.newpipe.extractor.channel.ChannelInfo +import org.schabi.newpipe.ui.components.metadata.ImageMetadataItem +import org.schabi.newpipe.ui.components.metadata.MetadataItem +import org.schabi.newpipe.ui.theme.AppTheme +import org.schabi.newpipe.util.Localization +import org.schabi.newpipe.util.NO_SERVICE_ID +import org.schabi.newpipe.util.image.ImageStrategy + +@Composable +fun AboutChannelSection(channelInfo: ChannelInfo) { + // This tab currently holds little information, so a lazy column isn't needed here. + Column( + modifier = Modifier.padding(12.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + val description = channelInfo.description + if (!description.isNullOrEmpty()) { + Text(text = description) + } + + val count = channelInfo.subscriberCount + if (count != -1L) { + MetadataItem( + title = R.string.metadata_subscribers, + value = Localization.shortCount(LocalContext.current, count) + ) + } + + ImageStrategy.choosePreferredImage(channelInfo.avatars)?.let { + ImageMetadataItem(R.string.metadata_avatars, channelInfo.avatars, it) + } + + ImageStrategy.choosePreferredImage(channelInfo.banners)?.let { + ImageMetadataItem(R.string.metadata_banners, channelInfo.banners, it) + } + + if (channelInfo.tags.isNotEmpty()) { + TagsSection(channelInfo.serviceId, channelInfo.tags) + } + } +} + +@Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +private fun AboutChannelSectionPreview() { + val info = ChannelInfo(NO_SERVICE_ID, "", "", "", "") + info.description = "This is an example description" + info.subscriberCount = 10 + + AppTheme { + Surface(color = MaterialTheme.colorScheme.background) { + AboutChannelSection(info) + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/metadata/ImageMetadataItem.kt b/app/src/main/java/org/schabi/newpipe/ui/components/metadata/ImageMetadataItem.kt index dce287f55ed..3df8c8cb196 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/metadata/ImageMetadataItem.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/metadata/ImageMetadataItem.kt @@ -3,7 +3,6 @@ package org.schabi.newpipe.ui.components.metadata import android.content.Context import android.content.res.Configuration import androidx.annotation.StringRes -import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.runtime.Composable @@ -38,14 +37,6 @@ fun ImageMetadataItem( MetadataItem(title = title, value = imageLinks) } -fun LazyListScope.imageMetadataItem(@StringRes title: Int, images: List) { - ImageStrategy.choosePreferredImage(images)?.let { - item { - ImageMetadataItem(title, images, it) - } - } -} - private fun convertImagesToLinks( context: Context, images: List, diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/metadata/MetadataItem.kt b/app/src/main/java/org/schabi/newpipe/ui/components/metadata/MetadataItem.kt index 29ead79156a..9f18e37b3e4 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/metadata/MetadataItem.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/metadata/MetadataItem.kt @@ -6,7 +6,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.lazy.LazyListScope +import androidx.compose.foundation.layout.width import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -35,24 +35,13 @@ fun MetadataItem(@StringRes title: Int, value: AnnotatedString) { verticalAlignment = Alignment.CenterVertically ) { Text( - modifier = Modifier.weight(0.3f), + modifier = Modifier.width(96.dp), textAlign = TextAlign.End, - text = stringResource(title).uppercase(), + text = stringResource(title), fontWeight = FontWeight.Bold ) - Text( - modifier = Modifier.weight(0.7f), - text = value - ) - } -} - -fun LazyListScope.metadataItem(@StringRes title: Int, value: String) { - if (value.isNotEmpty()) { - item { - MetadataItem(title, value) - } + Text(text = value) } } diff --git a/app/src/main/java/org/schabi/newpipe/ui/components/video/VideoDescriptionSection.kt b/app/src/main/java/org/schabi/newpipe/ui/components/video/VideoDescriptionSection.kt index 122e09017db..1d0903c8647 100644 --- a/app/src/main/java/org/schabi/newpipe/ui/components/video/VideoDescriptionSection.kt +++ b/app/src/main/java/org/schabi/newpipe/ui/components/video/VideoDescriptionSection.kt @@ -1,6 +1,7 @@ package org.schabi.newpipe.ui.components.video import android.content.res.Configuration +import androidx.annotation.StringRes import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn @@ -15,6 +16,7 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyListScope import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.material3.ExperimentalMaterial3Api @@ -43,19 +45,20 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import my.nanihadesuka.compose.LazyColumnScrollbar import org.schabi.newpipe.R +import org.schabi.newpipe.extractor.Image import org.schabi.newpipe.extractor.localization.DateWrapper import org.schabi.newpipe.extractor.stream.Description import org.schabi.newpipe.extractor.stream.StreamExtractor import org.schabi.newpipe.extractor.stream.StreamInfo import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.ui.components.common.DescriptionText +import org.schabi.newpipe.ui.components.metadata.ImageMetadataItem import org.schabi.newpipe.ui.components.metadata.MetadataItem import org.schabi.newpipe.ui.components.metadata.TagsSection -import org.schabi.newpipe.ui.components.metadata.imageMetadataItem -import org.schabi.newpipe.ui.components.metadata.metadataItem import org.schabi.newpipe.ui.theme.AppTheme import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.NO_SERVICE_ID +import org.schabi.newpipe.util.image.ImageStrategy import java.time.OffsetDateTime @OptIn(ExperimentalMaterial3Api::class) @@ -202,6 +205,22 @@ fun VideoDescriptionSection(streamInfo: StreamInfo) { } } +private fun LazyListScope.metadataItem(@StringRes title: Int, value: String) { + if (value.isNotEmpty()) { + item { + MetadataItem(title, value) + } + } +} + +private fun LazyListScope.imageMetadataItem(@StringRes title: Int, images: List) { + ImageStrategy.choosePreferredImage(images)?.let { + item { + ImageMetadataItem(title, images, it) + } + } +} + @Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO) @Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable