mirror of
https://github.com/TeamNewPipe/NewPipe.git
synced 2024-11-25 12:32:31 +01:00
Support obtaining multiple images from the extractor
This commit is contained in:
parent
e2de83188a
commit
af2375948d
@ -197,7 +197,7 @@ dependencies {
|
||||
// name and the commit hash with the commit hash of the (pushed) commit you want to test
|
||||
// This works thanks to JitPack: https://jitpack.io/
|
||||
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:95a3cc0a173bba28c179f9f9503b1010ec6bff21'
|
||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:3be76a6406d59f1fd8eedf5fab6552e6c2a3da76'
|
||||
implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
|
||||
|
||||
/** Checkstyle **/
|
||||
|
@ -75,7 +75,7 @@ public final class QueueItemMenuUtil {
|
||||
return true;
|
||||
case R.id.menu_item_share:
|
||||
shareText(context, item.getTitle(), item.getUrl(),
|
||||
item.getThumbnailUrl());
|
||||
item.getThumbnails());
|
||||
return true;
|
||||
case R.id.menu_item_download:
|
||||
fetchStreamInfoAndSaveToDatabase(context, item.getServiceId(), item.getUrl(),
|
||||
|
@ -7,6 +7,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
|
||||
import org.schabi.newpipe.database.stream.model.StreamEntity
|
||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.util.PicassoHelper
|
||||
|
||||
data class PlaylistStreamEntry(
|
||||
@Embedded
|
||||
@ -28,7 +29,7 @@ data class PlaylistStreamEntry(
|
||||
item.duration = streamEntity.duration
|
||||
item.uploaderName = streamEntity.uploader
|
||||
item.uploaderUrl = streamEntity.uploaderUrl
|
||||
item.thumbnailUrl = streamEntity.thumbnailUrl
|
||||
item.thumbnails = PicassoHelper.urlToImageList(streamEntity.thumbnailUrl)
|
||||
|
||||
return item
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import androidx.room.PrimaryKey;
|
||||
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
|
||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
|
||||
@ -69,8 +70,7 @@ public class PlaylistRemoteEntity implements PlaylistLocalItem {
|
||||
@Ignore
|
||||
public PlaylistRemoteEntity(final PlaylistInfo info) {
|
||||
this(info.getServiceId(), info.getName(), info.getUrl(),
|
||||
info.getThumbnailUrl() == null
|
||||
? info.getUploaderAvatarUrl() : info.getThumbnailUrl(),
|
||||
PicassoHelper.choosePreferredImage(info.getThumbnails()),
|
||||
info.getUploaderName(), info.getStreamCount());
|
||||
}
|
||||
|
||||
@ -84,7 +84,8 @@ public class PlaylistRemoteEntity implements PlaylistLocalItem {
|
||||
&& getStreamCount() == info.getStreamCount()
|
||||
&& TextUtils.equals(getName(), info.getName())
|
||||
&& TextUtils.equals(getUrl(), info.getUrl())
|
||||
&& TextUtils.equals(getThumbnailUrl(), info.getThumbnailUrl())
|
||||
&& TextUtils.equals(getThumbnailUrl(),
|
||||
PicassoHelper.choosePreferredImage(info.getThumbnails()))
|
||||
&& TextUtils.equals(getUploader(), info.getUploaderName());
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import org.schabi.newpipe.database.history.model.StreamHistoryEntity
|
||||
import org.schabi.newpipe.database.stream.model.StreamEntity
|
||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.util.PicassoHelper
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
class StreamStatisticsEntry(
|
||||
@ -30,7 +31,7 @@ class StreamStatisticsEntry(
|
||||
item.duration = streamEntity.duration
|
||||
item.uploaderName = streamEntity.uploader
|
||||
item.uploaderUrl = streamEntity.uploaderUrl
|
||||
item.thumbnailUrl = streamEntity.thumbnailUrl
|
||||
item.thumbnails = PicassoHelper.urlToImageList(streamEntity.thumbnailUrl)
|
||||
|
||||
return item
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.extractor.stream.StreamType
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem
|
||||
import org.schabi.newpipe.util.PicassoHelper
|
||||
import java.io.Serializable
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
@ -67,7 +68,7 @@ data class StreamEntity(
|
||||
constructor(item: StreamInfoItem) : this(
|
||||
serviceId = item.serviceId, url = item.url, title = item.name,
|
||||
streamType = item.streamType, duration = item.duration, uploader = item.uploaderName,
|
||||
uploaderUrl = item.uploaderUrl, thumbnailUrl = item.thumbnailUrl, viewCount = item.viewCount,
|
||||
uploaderUrl = item.uploaderUrl, thumbnailUrl = PicassoHelper.choosePreferredImage(item.thumbnails), viewCount = item.viewCount,
|
||||
textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(),
|
||||
isUploadDateApproximation = item.uploadDate?.isApproximation
|
||||
)
|
||||
@ -76,7 +77,7 @@ data class StreamEntity(
|
||||
constructor(info: StreamInfo) : this(
|
||||
serviceId = info.serviceId, url = info.url, title = info.name,
|
||||
streamType = info.streamType, duration = info.duration, uploader = info.uploaderName,
|
||||
uploaderUrl = info.uploaderUrl, thumbnailUrl = info.thumbnailUrl, viewCount = info.viewCount,
|
||||
uploaderUrl = info.uploaderUrl, thumbnailUrl = PicassoHelper.choosePreferredImage(info.thumbnails), viewCount = info.viewCount,
|
||||
textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(),
|
||||
isUploadDateApproximation = info.uploadDate?.isApproximation
|
||||
)
|
||||
@ -85,7 +86,8 @@ data class StreamEntity(
|
||||
constructor(item: PlayQueueItem) : this(
|
||||
serviceId = item.serviceId, url = item.url, title = item.title,
|
||||
streamType = item.streamType, duration = item.duration, uploader = item.uploader,
|
||||
uploaderUrl = item.uploaderUrl, thumbnailUrl = item.thumbnailUrl
|
||||
uploaderUrl = item.uploaderUrl,
|
||||
thumbnailUrl = PicassoHelper.choosePreferredImage(item.thumbnails)
|
||||
)
|
||||
|
||||
fun toStreamInfoItem(): StreamInfoItem {
|
||||
@ -93,7 +95,7 @@ data class StreamEntity(
|
||||
item.duration = duration
|
||||
item.uploaderName = uploader
|
||||
item.uploaderUrl = uploaderUrl
|
||||
item.thumbnailUrl = thumbnailUrl
|
||||
item.thumbnails = PicassoHelper.urlToImageList(thumbnailUrl)
|
||||
|
||||
if (viewCount != null) item.viewCount = viewCount as Long
|
||||
item.textualUploadDate = textualUploadDate
|
||||
|
@ -10,6 +10,7 @@ import androidx.room.PrimaryKey;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.util.Constants;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
|
||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
|
||||
@ -57,8 +58,8 @@ public class SubscriptionEntity {
|
||||
final SubscriptionEntity result = new SubscriptionEntity();
|
||||
result.setServiceId(info.getServiceId());
|
||||
result.setUrl(info.getUrl());
|
||||
result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(),
|
||||
info.getSubscriberCount());
|
||||
result.setData(info.getName(), PicassoHelper.choosePreferredImage(info.getAvatars()),
|
||||
info.getDescription(), info.getSubscriberCount());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -138,7 +139,7 @@ public class SubscriptionEntity {
|
||||
@Ignore
|
||||
public ChannelInfoItem toChannelInfoItem() {
|
||||
final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
||||
item.setThumbnailUrl(getAvatarUrl());
|
||||
item.setThumbnails(PicassoHelper.urlToImageList(getAvatarUrl()));
|
||||
item.setSubscriberCount(getSubscriberCount());
|
||||
item.setDescription(getDescription());
|
||||
return item;
|
||||
|
@ -17,6 +17,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.util.Localization;
|
||||
|
||||
import java.util.List;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import icepick.State;
|
||||
|
||||
@ -113,7 +114,7 @@ public class DescriptionFragment extends BaseDescriptionFragment {
|
||||
addMetadataItem(inflater, layout, true, R.string.metadata_host,
|
||||
streamInfo.getHost());
|
||||
addMetadataItem(inflater, layout, true, R.string.metadata_thumbnail_url,
|
||||
streamInfo.getThumbnailUrl());
|
||||
PicassoHelper.choosePreferredImage(streamInfo.getThumbnails()));
|
||||
}
|
||||
|
||||
private void addPrivacyMetadataItem(final LayoutInflater inflater, final LinearLayout layout) {
|
||||
|
@ -71,6 +71,7 @@ import org.schabi.newpipe.error.ErrorInfo;
|
||||
import org.schabi.newpipe.error.ErrorUtil;
|
||||
import org.schabi.newpipe.error.ReCaptchaActivity;
|
||||
import org.schabi.newpipe.error.UserAction;
|
||||
import org.schabi.newpipe.extractor.Image;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
||||
@ -483,7 +484,7 @@ public final class VideoDetailFragment
|
||||
});
|
||||
binding.detailControlsShare.setOnClickListener(makeOnClickListener(info ->
|
||||
ShareUtils.shareText(requireContext(), info.getName(), info.getUrl(),
|
||||
info.getThumbnailUrl())));
|
||||
info.getThumbnails())));
|
||||
binding.detailControlsOpenInBrowser.setOnClickListener(makeOnClickListener(info ->
|
||||
ShareUtils.openUrlInBrowser(requireContext(), info.getUrl())));
|
||||
binding.detailControlsPlayWithKodi.setOnClickListener(makeOnClickListener(info ->
|
||||
@ -723,7 +724,7 @@ public final class VideoDetailFragment
|
||||
final boolean isPlayerStopped = !isPlayerAvailable() || player.isStopped();
|
||||
if (playQueueItem != null && isPlayerStopped) {
|
||||
updateOverlayData(playQueueItem.getTitle(),
|
||||
playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
|
||||
playQueueItem.getUploader(), playQueueItem.getThumbnails());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1536,13 +1537,13 @@ public final class VideoDetailFragment
|
||||
binding.detailSecondaryControlPanel.setVisibility(View.GONE);
|
||||
|
||||
checkUpdateProgressInfo(info);
|
||||
PicassoHelper.loadDetailsThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
PicassoHelper.loadDetailsThumbnail(info.getThumbnails()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
.into(binding.detailThumbnailImageView);
|
||||
showMetaInfoInTextView(info.getMetaInfo(), binding.detailMetaInfoTextView,
|
||||
binding.detailMetaInfoSeparator, disposables);
|
||||
|
||||
if (!isPlayerAvailable() || player.isStopped()) {
|
||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnails());
|
||||
}
|
||||
|
||||
if (!info.getErrors().isEmpty()) {
|
||||
@ -1587,7 +1588,7 @@ public final class VideoDetailFragment
|
||||
binding.detailUploaderTextView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
PicassoHelper.loadAvatar(info.getUploaderAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
PicassoHelper.loadAvatar(info.getUploaderAvatars()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
.into(binding.detailSubChannelThumbnailView);
|
||||
binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
|
||||
binding.detailUploaderThumbnailView.setVisibility(View.GONE);
|
||||
@ -1619,10 +1620,10 @@ public final class VideoDetailFragment
|
||||
binding.detailUploaderTextView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
PicassoHelper.loadAvatar(info.getSubChannelAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
PicassoHelper.loadAvatar(info.getSubChannelAvatars()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
.into(binding.detailSubChannelThumbnailView);
|
||||
binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
|
||||
PicassoHelper.loadAvatar(info.getUploaderAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
PicassoHelper.loadAvatar(info.getUploaderAvatars()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
.into(binding.detailUploaderThumbnailView);
|
||||
binding.detailUploaderThumbnailView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@ -1797,7 +1798,7 @@ public final class VideoDetailFragment
|
||||
return;
|
||||
}
|
||||
|
||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnails());
|
||||
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) {
|
||||
return;
|
||||
}
|
||||
@ -1826,7 +1827,7 @@ public final class VideoDetailFragment
|
||||
if (currentInfo != null) {
|
||||
updateOverlayData(currentInfo.getName(),
|
||||
currentInfo.getUploaderName(),
|
||||
currentInfo.getThumbnailUrl());
|
||||
currentInfo.getThumbnails());
|
||||
}
|
||||
updateOverlayPlayQueueButtonVisibility();
|
||||
}
|
||||
@ -2191,7 +2192,7 @@ public final class VideoDetailFragment
|
||||
playerHolder.stopService();
|
||||
setInitialData(0, null, "", null);
|
||||
currentInfo = null;
|
||||
updateOverlayData(null, null, null);
|
||||
updateOverlayData(null, null, List.of());
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
@ -2373,11 +2374,11 @@ public final class VideoDetailFragment
|
||||
|
||||
private void updateOverlayData(@Nullable final String overlayTitle,
|
||||
@Nullable final String uploader,
|
||||
@Nullable final String thumbnailUrl) {
|
||||
@NonNull final List<Image> thumbnails) {
|
||||
binding.overlayTitleTextView.setText(isEmpty(overlayTitle) ? "" : overlayTitle);
|
||||
binding.overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
|
||||
binding.overlayThumbnail.setImageDrawable(null);
|
||||
PicassoHelper.loadDetailsThumbnail(thumbnailUrl).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
PicassoHelper.loadDetailsThumbnail(thumbnails).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||
.into(binding.overlayThumbnail);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ 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 org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -100,8 +101,8 @@ public class ChannelAboutFragment extends BaseDescriptionFragment {
|
||||
}
|
||||
|
||||
addMetadataItem(inflater, layout, true, R.string.metadata_avatar_url,
|
||||
channelInfo.getAvatarUrl());
|
||||
PicassoHelper.choosePreferredImage(channelInfo.getAvatars()));
|
||||
addMetadataItem(inflater, layout, true, R.string.metadata_banner_url,
|
||||
channelInfo.getBannerUrl());
|
||||
PicassoHelper.choosePreferredImage(channelInfo.getBanners()));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package org.schabi.newpipe.fragments.list.channel;
|
||||
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
||||
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
|
||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
|
||||
@ -234,7 +233,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
||||
case R.id.menu_item_share:
|
||||
if (currentInfo != null) {
|
||||
ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl(),
|
||||
currentInfo.getAvatarUrl());
|
||||
currentInfo.getAvatars());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -355,7 +354,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
||||
channel.setServiceId(info.getServiceId());
|
||||
channel.setUrl(info.getUrl());
|
||||
channel.setData(info.getName(),
|
||||
info.getAvatarUrl(),
|
||||
PicassoHelper.choosePreferredImage(info.getAvatars()),
|
||||
info.getDescription(),
|
||||
info.getSubscriberCount());
|
||||
channelSubscription = null;
|
||||
@ -579,17 +578,17 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
||||
currentInfo = result;
|
||||
setInitialData(result.getServiceId(), result.getOriginalUrl(), result.getName());
|
||||
|
||||
if (PicassoHelper.getShouldLoadImages() && !isBlank(result.getBannerUrl())) {
|
||||
PicassoHelper.loadBanner(result.getBannerUrl()).tag(PICASSO_CHANNEL_TAG)
|
||||
if (PicassoHelper.getShouldLoadImages() && !result.getBanners().isEmpty()) {
|
||||
PicassoHelper.loadBanner(result.getBanners()).tag(PICASSO_CHANNEL_TAG)
|
||||
.into(binding.channelBannerImage);
|
||||
} else {
|
||||
// do not waste space for the banner, if the user disabled images or there is not one
|
||||
binding.channelBannerImage.setImageDrawable(null);
|
||||
}
|
||||
|
||||
PicassoHelper.loadAvatar(result.getAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
|
||||
PicassoHelper.loadAvatar(result.getAvatars()).tag(PICASSO_CHANNEL_TAG)
|
||||
.into(binding.channelAvatarView);
|
||||
PicassoHelper.loadAvatar(result.getParentChannelAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
|
||||
PicassoHelper.loadAvatar(result.getParentChannelAvatars()).tag(PICASSO_CHANNEL_TAG)
|
||||
.into(binding.subChannelAvatarView);
|
||||
|
||||
binding.channelTitleView.setText(result.getName());
|
||||
|
@ -234,7 +234,7 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||
break;
|
||||
case R.id.menu_item_share:
|
||||
ShareUtils.shareText(requireContext(), name, url,
|
||||
currentInfo == null ? null : currentInfo.getThumbnailUrl());
|
||||
currentInfo == null ? List.of() : currentInfo.getThumbnails());
|
||||
break;
|
||||
case R.id.menu_item_bookmark:
|
||||
onBookmarkClicked();
|
||||
@ -299,7 +299,6 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||
|
||||
playlistControlBinding.getRoot().setVisibility(View.VISIBLE);
|
||||
|
||||
final String avatarUrl = result.getUploaderAvatarUrl();
|
||||
if (result.getServiceId() == ServiceList.YouTube.getServiceId()
|
||||
&& (YoutubeParsingHelper.isYoutubeMixId(result.getId())
|
||||
|| YoutubeParsingHelper.isYoutubeMusicMixId(result.getId()))) {
|
||||
@ -315,7 +314,7 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||
R.drawable.ic_radio)
|
||||
);
|
||||
} else {
|
||||
PicassoHelper.loadAvatar(avatarUrl).tag(PICASSO_PLAYLIST_TAG)
|
||||
PicassoHelper.loadAvatar(result.getUploaderAvatars()).tag(PICASSO_PLAYLIST_TAG)
|
||||
.into(headerBinding.uploaderAvatarView);
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ public enum StreamDialogDefaultEntry {
|
||||
|
||||
SHARE(R.string.share, (fragment, item) ->
|
||||
ShareUtils.shareText(fragment.requireContext(), item.getName(), item.getUrl(),
|
||||
item.getThumbnailUrl())),
|
||||
item.getThumbnails())),
|
||||
|
||||
/**
|
||||
* Opens a {@link DownloadDialog} after fetching some stream info.
|
||||
|
@ -56,7 +56,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
||||
itemAdditionalDetailView.setText(getDetailLine(item));
|
||||
}
|
||||
|
||||
PicassoHelper.loadAvatar(item.getThumbnailUrl()).into(itemThumbnailView);
|
||||
PicassoHelper.loadAvatar(item.getThumbnails()).into(itemThumbnailView);
|
||||
|
||||
itemView.setOnClickListener(view -> {
|
||||
if (itemBuilder.getOnChannelSelectedListener() != null) {
|
||||
|
@ -97,7 +97,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||
}
|
||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
||||
|
||||
PicassoHelper.loadAvatar(item.getUploaderAvatarUrl()).into(itemThumbnailView);
|
||||
PicassoHelper.loadAvatar(item.getUploaderAvatars()).into(itemThumbnailView);
|
||||
if (PicassoHelper.getShouldLoadImages()) {
|
||||
itemThumbnailView.setVisibility(View.VISIBLE);
|
||||
itemRoot.setPadding(commentVerticalPadding, commentVerticalPadding,
|
||||
|
@ -46,7 +46,7 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
||||
.localizeStreamCountMini(itemStreamCountView.getContext(), item.getStreamCount()));
|
||||
itemUploaderView.setText(item.getUploaderName());
|
||||
|
||||
PicassoHelper.loadPlaylistThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
|
||||
PicassoHelper.loadPlaylistThumbnail(item.getThumbnails()).into(itemThumbnailView);
|
||||
|
||||
itemView.setOnClickListener(view -> {
|
||||
if (itemBuilder.getOnPlaylistSelectedListener() != null) {
|
||||
|
@ -87,7 +87,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
||||
}
|
||||
|
||||
// Default thumbnail is shown on error, while loading and if the url is empty
|
||||
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
|
||||
PicassoHelper.loadThumbnail(item.getThumbnails()).into(itemThumbnailView);
|
||||
|
||||
itemView.setOnClickListener(view -> {
|
||||
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
||||
|
@ -58,6 +58,7 @@ import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard
|
||||
import org.schabi.newpipe.streams.io.StoredFileHelper
|
||||
import org.schabi.newpipe.util.NavigationHelper
|
||||
import org.schabi.newpipe.util.OnClickGesture
|
||||
import org.schabi.newpipe.util.PicassoHelper
|
||||
import org.schabi.newpipe.util.ServiceHelper
|
||||
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountChannels
|
||||
import org.schabi.newpipe.util.external_communication.ShareUtils
|
||||
@ -342,7 +343,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
||||
when (i) {
|
||||
0 -> ShareUtils.shareText(
|
||||
requireContext(), selectedItem.name, selectedItem.url,
|
||||
selectedItem.thumbnailUrl
|
||||
PicassoHelper.choosePreferredImage(selectedItem.thumbnails)
|
||||
)
|
||||
1 -> ShareUtils.openUrlInBrowser(requireContext(), selectedItem.url)
|
||||
2 -> deleteChannel(selectedItem)
|
||||
|
@ -19,6 +19,7 @@ import org.schabi.newpipe.extractor.feed.FeedInfo
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.local.feed.FeedDatabaseManager
|
||||
import org.schabi.newpipe.util.ExtractorHelper
|
||||
import org.schabi.newpipe.util.PicassoHelper
|
||||
|
||||
class SubscriptionManager(context: Context) {
|
||||
private val database = NewPipeDatabase.getInstance(context)
|
||||
@ -71,7 +72,12 @@ class SubscriptionManager(context: Context) {
|
||||
subscriptionTable.getSubscription(info.serviceId, info.url)
|
||||
.flatMapCompletable {
|
||||
Completable.fromRunnable {
|
||||
it.setData(info.name, info.avatarUrl, info.description, info.subscriberCount)
|
||||
it.setData(
|
||||
info.name,
|
||||
PicassoHelper.choosePreferredImage(info.avatars),
|
||||
info.description,
|
||||
info.subscriberCount
|
||||
)
|
||||
subscriptionTable.update(it)
|
||||
}
|
||||
}
|
||||
@ -99,7 +105,7 @@ class SubscriptionManager(context: Context) {
|
||||
} else if (info is ChannelInfo) {
|
||||
subscriptionEntity.setData(
|
||||
info.name,
|
||||
info.avatarUrl,
|
||||
PicassoHelper.choosePreferredImage(info.avatars),
|
||||
info.description,
|
||||
info.subscriberCount
|
||||
)
|
||||
|
@ -39,7 +39,7 @@ class ChannelItem(
|
||||
itemChannelDescriptionView.text = infoItem.description
|
||||
}
|
||||
|
||||
PicassoHelper.loadAvatar(infoItem.thumbnailUrl).into(itemThumbnailView)
|
||||
PicassoHelper.loadAvatar(infoItem.thumbnails).into(itemThumbnailView)
|
||||
|
||||
gesturesListener?.run {
|
||||
viewHolder.root.setOnClickListener { selected(infoItem) }
|
||||
|
@ -87,6 +87,7 @@ import org.schabi.newpipe.error.ErrorInfo;
|
||||
import org.schabi.newpipe.error.ErrorUtil;
|
||||
import org.schabi.newpipe.error.UserAction;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.Image;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
@ -805,10 +806,10 @@ public final class Player implements PlaybackListener, Listener {
|
||||
};
|
||||
}
|
||||
|
||||
private void loadCurrentThumbnail(final String url) {
|
||||
private void loadCurrentThumbnail(final List<Image> thumbnails) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Thumbnail - loadCurrentThumbnail() called with url = ["
|
||||
+ (url == null ? "null" : url) + "]");
|
||||
Log.d(TAG, "Thumbnail - loadCurrentThumbnail() called with thumbnails = ["
|
||||
+ thumbnails.size() + "]");
|
||||
}
|
||||
|
||||
// first cancel any previous loading
|
||||
@ -817,12 +818,12 @@ public final class Player implements PlaybackListener, Listener {
|
||||
// Unset currentThumbnail, since it is now outdated. This ensures it is not used in media
|
||||
// session metadata while the new thumbnail is being loaded by Picasso.
|
||||
onThumbnailLoaded(null);
|
||||
if (isNullOrEmpty(url)) {
|
||||
if (thumbnails.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// scale down the notification thumbnail for performance
|
||||
PicassoHelper.loadScaledDownThumbnail(context, url)
|
||||
PicassoHelper.loadScaledDownThumbnail(context, thumbnails)
|
||||
.tag(PICASSO_PLAYER_THUMBNAIL_TAG)
|
||||
.into(currentThumbnailTarget);
|
||||
}
|
||||
@ -1792,7 +1793,7 @@ public final class Player implements PlaybackListener, Listener {
|
||||
|
||||
maybeAutoQueueNextStream(info);
|
||||
|
||||
loadCurrentThumbnail(info.getThumbnailUrl());
|
||||
loadCurrentThumbnail(info.getThumbnails());
|
||||
registerStreamViewed();
|
||||
|
||||
notifyMetadataUpdateToListeners();
|
||||
|
@ -3,6 +3,7 @@ package org.schabi.newpipe.player.mediaitem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@ -74,7 +75,7 @@ public final class ExceptionTag implements MediaItemTag {
|
||||
|
||||
@Override
|
||||
public String getThumbnailUrl() {
|
||||
return item.getThumbnailUrl();
|
||||
return PicassoHelper.choosePreferredImage(item.getThumbnails());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6,6 +6,7 @@ import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
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.util.PicassoHelper;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -95,7 +96,7 @@ public final class StreamInfoTag implements MediaItemTag {
|
||||
|
||||
@Override
|
||||
public String getThumbnailUrl() {
|
||||
return streamInfo.getThumbnailUrl();
|
||||
return PicassoHelper.choosePreferredImage(streamInfo.getThumbnails());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
import org.schabi.newpipe.player.Player;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -137,7 +138,8 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
|
||||
.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, player.getPlayQueue().size());
|
||||
descBuilder.setExtras(additionalMetadata);
|
||||
|
||||
final Uri thumbnailUri = Uri.parse(item.getThumbnailUrl());
|
||||
final Uri thumbnailUri = Uri.parse(
|
||||
PicassoHelper.choosePreferredImage(item.getThumbnails()));
|
||||
if (thumbnailUri != null) {
|
||||
descBuilder.setIconUri(thumbnailUri);
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ package org.schabi.newpipe.player.playqueue;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.schabi.newpipe.extractor.Image;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.util.ExtractorHelper;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.rxjava3.core.Single;
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||
@ -24,7 +26,7 @@ public class PlayQueueItem implements Serializable {
|
||||
private final int serviceId;
|
||||
private final long duration;
|
||||
@NonNull
|
||||
private final String thumbnailUrl;
|
||||
private final List<Image> thumbnails;
|
||||
@NonNull
|
||||
private final String uploader;
|
||||
private final String uploaderUrl;
|
||||
@ -38,7 +40,7 @@ public class PlayQueueItem implements Serializable {
|
||||
|
||||
PlayQueueItem(@NonNull final StreamInfo info) {
|
||||
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
|
||||
info.getThumbnailUrl(), info.getUploaderName(),
|
||||
info.getThumbnails(), info.getUploaderName(),
|
||||
info.getUploaderUrl(), info.getStreamType());
|
||||
|
||||
if (info.getStartPosition() > 0) {
|
||||
@ -48,20 +50,20 @@ public class PlayQueueItem implements Serializable {
|
||||
|
||||
PlayQueueItem(@NonNull final StreamInfoItem item) {
|
||||
this(item.getName(), item.getUrl(), item.getServiceId(), item.getDuration(),
|
||||
item.getThumbnailUrl(), item.getUploaderName(),
|
||||
item.getThumbnails(), item.getUploaderName(),
|
||||
item.getUploaderUrl(), item.getStreamType());
|
||||
}
|
||||
|
||||
@SuppressWarnings("ParameterNumber")
|
||||
private PlayQueueItem(@Nullable final String name, @Nullable final String url,
|
||||
final int serviceId, final long duration,
|
||||
@Nullable final String thumbnailUrl, @Nullable final String uploader,
|
||||
final List<Image> thumbnails, @Nullable final String uploader,
|
||||
final String uploaderUrl, @NonNull final StreamType streamType) {
|
||||
this.title = name != null ? name : EMPTY_STRING;
|
||||
this.url = url != null ? url : EMPTY_STRING;
|
||||
this.serviceId = serviceId;
|
||||
this.duration = duration;
|
||||
this.thumbnailUrl = thumbnailUrl != null ? thumbnailUrl : EMPTY_STRING;
|
||||
this.thumbnails = thumbnails;
|
||||
this.uploader = uploader != null ? uploader : EMPTY_STRING;
|
||||
this.uploaderUrl = uploaderUrl;
|
||||
this.streamType = streamType;
|
||||
@ -88,8 +90,8 @@ public class PlayQueueItem implements Serializable {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getThumbnailUrl() {
|
||||
return thumbnailUrl;
|
||||
public List<Image> getThumbnails() {
|
||||
return thumbnails;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -33,7 +33,7 @@ public class PlayQueueItemBuilder {
|
||||
holder.itemDurationView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(holder.itemThumbnailView);
|
||||
PicassoHelper.loadThumbnail(item.getThumbnails()).into(holder.itemThumbnailView);
|
||||
|
||||
holder.itemRoot.setOnClickListener(view -> {
|
||||
if (onItemClickListener != null) {
|
||||
|
@ -740,7 +740,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
||||
String videoUrl = player.getVideoUrl();
|
||||
videoUrl += ("&t=" + seconds);
|
||||
ShareUtils.shareText(context, currentItem.getTitle(),
|
||||
videoUrl, currentItem.getThumbnailUrl());
|
||||
videoUrl, currentItem.getThumbnails());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -226,7 +226,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
||||
final PlayQueueItem currentItem = player.getCurrentItem();
|
||||
if (currentItem != null) {
|
||||
ShareUtils.shareText(context, currentItem.getTitle(),
|
||||
player.getVideoUrlAtCurrentTime(), currentItem.getThumbnailUrl());
|
||||
player.getVideoUrlAtCurrentTime(), currentItem.getThumbnails());
|
||||
}
|
||||
}));
|
||||
binding.share.setOnLongClickListener(v -> {
|
||||
|
@ -1,13 +1,14 @@
|
||||
package org.schabi.newpipe.util;
|
||||
|
||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.BitmapCompat;
|
||||
|
||||
@ -19,9 +20,13 @@ import com.squareup.picasso.RequestCreator;
|
||||
import com.squareup.picasso.Transformation;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.Image;
|
||||
import org.schabi.newpipe.extractor.Image.ResolutionLevel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
@ -42,6 +47,7 @@ public final class PicassoHelper {
|
||||
private static Picasso picassoInstance;
|
||||
|
||||
private static boolean shouldLoadImages;
|
||||
private static ResolutionLevel preferredResolutionLevel = ResolutionLevel.HIGH;
|
||||
|
||||
public static void init(final Context context) {
|
||||
picassoCache = new LruCache(10 * 1024 * 1024);
|
||||
@ -96,20 +102,33 @@ public final class PicassoHelper {
|
||||
}
|
||||
|
||||
|
||||
public static RequestCreator loadAvatar(final List<Image> images) {
|
||||
return loadImageDefault(images, R.drawable.placeholder_person);
|
||||
}
|
||||
|
||||
public static RequestCreator loadAvatar(final String url) {
|
||||
return loadImageDefault(url, R.drawable.placeholder_person);
|
||||
}
|
||||
|
||||
public static RequestCreator loadThumbnail(final List<Image> images) {
|
||||
return loadImageDefault(images, R.drawable.placeholder_thumbnail_video);
|
||||
}
|
||||
|
||||
public static RequestCreator loadThumbnail(final String url) {
|
||||
return loadImageDefault(url, R.drawable.placeholder_thumbnail_video);
|
||||
}
|
||||
|
||||
public static RequestCreator loadDetailsThumbnail(final String url) {
|
||||
return loadImageDefault(url, R.drawable.placeholder_thumbnail_video, false);
|
||||
public static RequestCreator loadDetailsThumbnail(final List<Image> images) {
|
||||
return loadImageDefault(choosePreferredImage(images),
|
||||
R.drawable.placeholder_thumbnail_video, false);
|
||||
}
|
||||
|
||||
public static RequestCreator loadBanner(final String url) {
|
||||
return loadImageDefault(url, R.drawable.placeholder_channel_banner);
|
||||
public static RequestCreator loadBanner(final List<Image> images) {
|
||||
return loadImageDefault(images, R.drawable.placeholder_channel_banner);
|
||||
}
|
||||
|
||||
public static RequestCreator loadPlaylistThumbnail(final List<Image> images) {
|
||||
return loadImageDefault(images, R.drawable.placeholder_thumbnail_playlist);
|
||||
}
|
||||
|
||||
public static RequestCreator loadPlaylistThumbnail(final String url) {
|
||||
@ -125,9 +144,10 @@ public final class PicassoHelper {
|
||||
}
|
||||
|
||||
|
||||
public static RequestCreator loadScaledDownThumbnail(final Context context, final String url) {
|
||||
public static RequestCreator loadScaledDownThumbnail(final Context context,
|
||||
final List<Image> images) {
|
||||
// scale down the notification thumbnail for performance
|
||||
return PicassoHelper.loadThumbnail(url)
|
||||
return PicassoHelper.loadThumbnail(images)
|
||||
.transform(new Transformation() {
|
||||
@Override
|
||||
public Bitmap transform(final Bitmap source) {
|
||||
@ -180,13 +200,20 @@ public final class PicassoHelper {
|
||||
}
|
||||
|
||||
|
||||
private static RequestCreator loadImageDefault(final String url, final int placeholderResId) {
|
||||
private static RequestCreator loadImageDefault(final List<Image> images,
|
||||
final int placeholderResId) {
|
||||
return loadImageDefault(choosePreferredImage(images), placeholderResId);
|
||||
}
|
||||
|
||||
private static RequestCreator loadImageDefault(final String url,
|
||||
final int placeholderResId) {
|
||||
return loadImageDefault(url, placeholderResId, true);
|
||||
}
|
||||
|
||||
private static RequestCreator loadImageDefault(final String url, final int placeholderResId,
|
||||
private static RequestCreator loadImageDefault(@Nullable final String url,
|
||||
final int placeholderResId,
|
||||
final boolean showPlaceholderWhileLoading) {
|
||||
if (!shouldLoadImages || isBlank(url)) {
|
||||
if (isNullOrEmpty(url)) {
|
||||
return picassoInstance
|
||||
.load((String) null)
|
||||
.placeholder(placeholderResId) // show placeholder when no image should load
|
||||
@ -201,4 +228,44 @@ public final class PicassoHelper {
|
||||
return requestCreator;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String choosePreferredImage(final List<Image> images) {
|
||||
if (!shouldLoadImages) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Comparator<Image> comparator;
|
||||
switch (preferredResolutionLevel) {
|
||||
case HIGH:
|
||||
comparator = Comparator.comparingInt(Image::getHeight).reversed();
|
||||
break;
|
||||
default:
|
||||
case UNKNOWN:
|
||||
case MEDIUM:
|
||||
comparator = Comparator.comparingInt(image -> Math.abs(image.getHeight() - 450));
|
||||
break;
|
||||
case LOW:
|
||||
comparator = Comparator.comparingInt(Image::getHeight);
|
||||
break;
|
||||
}
|
||||
|
||||
return images.stream()
|
||||
.filter(image -> image.getEstimatedResolutionLevel() != ResolutionLevel.UNKNOWN)
|
||||
.min(comparator)
|
||||
.map(Image::getUrl)
|
||||
.orElseGet(() -> images.stream()
|
||||
.findAny()
|
||||
.map(Image::getUrl)
|
||||
.orElse(null));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static List<Image> urlToImageList(@Nullable final String url) {
|
||||
if (url == null) {
|
||||
return List.of();
|
||||
} else {
|
||||
return List.of(new Image(url, -1, -1, ResolutionLevel.UNKNOWN));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,10 +23,12 @@ import androidx.core.content.FileProvider;
|
||||
|
||||
import org.schabi.newpipe.BuildConfig;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.Image;
|
||||
import org.schabi.newpipe.util.PicassoHelper;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
public final class ShareUtils {
|
||||
private static final String TAG = ShareUtils.class.getSimpleName();
|
||||
@ -261,6 +263,29 @@ public final class ShareUtils {
|
||||
openAppChooser(context, shareIntent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the android share sheet to share a content.
|
||||
*
|
||||
* <p>
|
||||
* For Android 10+ users, a content preview is shown, which includes the title of the shared
|
||||
* content and an image preview the content, if its URL is not null or empty and its
|
||||
* corresponding image is in the image cache.
|
||||
* </p>
|
||||
*
|
||||
* @param context the context to use
|
||||
* @param title the title of the content
|
||||
* @param content the content to share
|
||||
* @param images a set of possible {@link Image}s of the subject, among which to choose with
|
||||
* {@link PicassoHelper#choosePreferredImage(List)} since that's likely to
|
||||
* provide an image that is in Picasso's cache
|
||||
*/
|
||||
public static void shareText(@NonNull final Context context,
|
||||
@NonNull final String title,
|
||||
final String content,
|
||||
final List<Image> images) {
|
||||
shareText(context, title, content, PicassoHelper.choosePreferredImage(images));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the android share sheet to share a content.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user