Locked content support

This commit is contained in:
Kelvin 2023-11-17 00:34:21 +01:00
parent 6df8f84421
commit 0c1822b118
31 changed files with 1030 additions and 36 deletions

View file

@ -211,6 +211,16 @@ class PlatformNestedMediaContent extends PlatformContent {
this.contentThumbnails = obj.contentThumbnails ?? new Thumbnails();
}
}
class PlatformLockedContent extends PlatformContent {
constructor(obj) {
super(obj, 70);
obj = obj ?? {};
this.contentName = obj.contentName;
this.contentThumbnails = obj.contentThumbnails ?? new Thumbnails();
this.unlockUrl = obj.unlockUrl ?? "";
this.lockDescription = obj.lockDescription;
}
}
class PlatformVideo extends PlatformContent {
constructor(obj) {
super(obj, 1);

View file

@ -360,6 +360,15 @@ class Settings : FragmentedStorageFileJson() {
var backgroundSwitchToAudio: Boolean = true;
}
@FormField(R.string.comments, "group", R.string.comments_description, 4)
var comments = CommentSettings();
@Serializable
class CommentSettings {
@FormField(R.string.default_comment_section, FieldForm.DROPDOWN, -1, 0)
@DropdownFieldOptionsId(R.array.comment_sections)
var defaultCommentSection: Int = 0;
}
@FormField(R.string.downloads, "group", R.string.configure_downloading_of_videos, 5)
var downloads = Downloads();
@Serializable

View file

@ -13,6 +13,7 @@ enum class ContentType(val value: Int) {
NESTED_VIDEO(11),
LOCKED(70),
PLACEHOLDER(90),
DEFERRED(91);

View file

@ -0,0 +1,13 @@
package com.futo.platformplayer.api.media.models.locked
import com.futo.platformplayer.api.media.models.Thumbnails
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
interface IPlatformLockedContent: IPlatformContent {
val lockContentType: ContentType;
val lockDescription: String?;
val unlockUrl: String?;
val contentName: String?;
val contentThumbnails: Thumbnails;
}

View file

@ -2,6 +2,7 @@ package com.futo.platformplayer.api.media.models.video
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.locked.IPlatformLockedContent
import com.futo.platformplayer.api.media.models.nested.IPlatformNestedContent
import com.futo.platformplayer.api.media.models.post.IPlatformPost
import com.futo.platformplayer.serializers.PlatformContentSerializer
@ -18,6 +19,7 @@ interface SerializedPlatformContent: IPlatformContent {
ContentType.MEDIA -> SerializedPlatformVideo.fromVideo(content as IPlatformVideo);
ContentType.NESTED_VIDEO -> SerializedPlatformNestedContent.fromNested(content as IPlatformNestedContent);
ContentType.POST -> SerializedPlatformPost.fromPost(content as IPlatformPost);
ContentType.LOCKED -> SerializedPlatformLockedContent.fromLocked(content as IPlatformLockedContent);
else -> throw NotImplementedError("Content type ${content.contentType} not implemented");
};
}

View file

@ -0,0 +1,62 @@
package com.futo.platformplayer.api.media.models.video
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.Serializer
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.Thumbnails
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.locked.IPlatformLockedContent
import com.futo.platformplayer.api.media.models.nested.IPlatformNestedContent
import com.futo.platformplayer.serializers.OffsetDateTimeNullableSerializer
import com.futo.platformplayer.states.StatePlatform
import com.futo.polycentric.core.combineHashCodes
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.time.OffsetDateTime
@kotlinx.serialization.Serializable
open class SerializedPlatformLockedContent(
override val id: PlatformID,
override val name: String,
override val author: PlatformAuthorLink,
@kotlinx.serialization.Serializable(with = OffsetDateTimeNullableSerializer::class)
override val datetime: OffsetDateTime?,
override val url: String,
override val shareUrl: String,
override val lockContentType: ContentType,
override val contentName: String?,
override val lockDescription: String? = null,
override val unlockUrl: String? = null,
override val contentThumbnails: Thumbnails
) : IPlatformLockedContent, SerializedPlatformContent {
final override val contentType: ContentType get() = ContentType.LOCKED;
override fun toJson() : String {
return Json.encodeToString(this);
}
override fun fromJson(str : String) : SerializedPlatformLockedContent {
return Serializer.json.decodeFromString<SerializedPlatformLockedContent>(str);
}
override fun fromJsonArray(str : String) : Array<SerializedPlatformContent> {
return Serializer.json.decodeFromString<Array<SerializedPlatformContent>>(str);
}
companion object {
fun fromLocked(content: IPlatformLockedContent) : SerializedPlatformLockedContent {
return SerializedPlatformLockedContent(
content.id,
content.name,
content.author,
content.datetime,
content.url,
content.shareUrl,
content.lockContentType,
content.contentName,
content.lockDescription,
content.unlockUrl,
content.contentThumbnails
);
}
}
}

View file

@ -23,6 +23,7 @@ interface IJSContent: IPlatformContent {
ContentType.POST -> JSPost(config, obj);
ContentType.NESTED_VIDEO -> JSNestedMediaContent(config, obj);
ContentType.PLAYLIST -> JSPlaylist(config, obj);
ContentType.LOCKED -> JSLockedContent(config, obj);
else -> throw NotImplementedError("Unknown content type ${type}");
}
}

View file

@ -0,0 +1,36 @@
package com.futo.platformplayer.api.media.platforms.js.models
import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.api.media.models.Thumbnails
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.locked.IPlatformLockedContent
import com.futo.platformplayer.api.media.models.nested.IPlatformNestedContent
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
import com.futo.platformplayer.getOrDefault
import com.futo.platformplayer.getOrThrow
import com.futo.platformplayer.states.StatePlatform
//TODO: Refactor into video-only
class JSLockedContent: IPlatformLockedContent, JSContent {
override val contentType: ContentType get() = ContentType.LOCKED;
override val lockContentType: ContentType get() = ContentType.MEDIA;
override val lockDescription: String?;
override val unlockUrl: String?;
override val contentName: String?;
override val contentThumbnails: Thumbnails;
constructor(config: SourcePluginConfig, obj: V8ValueObject): super(config, obj) {
val contextName = "PlatformLockedContent";
this.contentName = obj.getOrDefault(config, "contentName", contextName, null);
this.contentThumbnails = obj.getOrDefault<V8ValueObject?>(config, "contentThumbnails", contextName, null)?.let {
return@let Thumbnails.fromV8(config, it);
} ?: Thumbnails();
lockDescription = obj.getOrDefault(config, "lockDescription", contextName, null);
unlockUrl = obj.getOrDefault(config, "unlockUrl", contextName, null);
}
}

View file

@ -59,8 +59,6 @@ abstract class JSPager<T> : IPager<T> {
}
override fun getResults(): List<T> {
warnIfMainThread("JSPager.getResults");
val previousResults = _lastResults?.let {
if(!_resultChanged)
return@let it;
@ -70,6 +68,7 @@ abstract class JSPager<T> : IPager<T> {
if(previousResults != null)
return previousResults;
warnIfMainThread("JSPager.getResults");
val items = pager.getOrThrow<V8ValueArray>(config, "results", "JSPager");
val newResults = items.toArray()
.map { convertResult(it as V8ValueObject) }

View file

@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
@ -13,7 +12,6 @@ import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.UISlideOverlays
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
import com.futo.platformplayer.api.media.models.contents.ContentType
@ -36,7 +34,7 @@ import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
import com.futo.platformplayer.states.StatePolycentric
import com.futo.platformplayer.states.StateSubscriptions
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.PreviewContentListAdapter
import com.futo.platformplayer.views.adapters.feedtypes.PreviewContentListAdapter
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
import kotlinx.coroutines.Dispatchers
@ -56,6 +54,7 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
val onContentClicked = Event2<IPlatformContent, Long>();
val onContentUrlClicked = Event2<String, ContentType>();
val onUrlClicked = Event1<String>();
val onChannelClicked = Event1<PlatformAuthorLink>();
val onAddToClicked = Event1<IPlatformContent>();
val onAddToQueueClicked = Event1<IPlatformContent>();
@ -75,15 +74,14 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
}
private val _taskLoadVideos = TaskHandler<IPlatformChannel, IPager<IPlatformContent>>({lifecycleScope}, {
return@TaskHandler getContentPager(it);
val livePager = getContentPager(it);
return@TaskHandler if(_channel?.let { StateSubscriptions.instance.isSubscribed(it) } == true)
ChannelContentCache.cachePagerResults(lifecycleScope, livePager);
else livePager;
}).success { livePager ->
setLoading(false);
val pager = if(_channel?.let { StateSubscriptions.instance.isSubscribed(it) } == true)
ChannelContentCache.cachePagerResults(lifecycleScope, livePager);
else livePager;
setPager(pager);
setPager(livePager);
}
.exception<ScriptCaptchaRequiredException> { }
.exception<Throwable> {
@ -155,6 +153,7 @@ class ChannelContentsFragment : Fragment(), IChannelTabFragment {
_adapterResults = PreviewContentListAdapter(view.context, FeedStyle.THUMBNAIL, _results).apply {
this.onContentUrlClicked.subscribe(this@ChannelContentsFragment.onContentUrlClicked::emit);
this.onUrlClicked.subscribe(this@ChannelContentsFragment.onUrlClicked::emit);
this.onContentClicked.subscribe(this@ChannelContentsFragment.onContentClicked::emit);
this.onChannelClicked.subscribe(this@ChannelContentsFragment.onChannelClicked::emit);
this.onAddToClicked.subscribe(this@ChannelContentsFragment.onAddToClicked::emit);

View file

@ -210,6 +210,9 @@ class ChannelFragment : MainFragment() {
UIDialogs.toast(context, "Queued [$name]", false);
}
}
adapter.onUrlClicked.subscribe { url ->
fragment.navigate<BrowserFragment>(url);
}
adapter.onContentUrlClicked.subscribe { url, contentType ->
when(contentType) {
ContentType.MEDIA -> {

View file

@ -1,6 +1,5 @@
package com.futo.platformplayer.fragment.mainactivity.main
import android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import android.view.LayoutInflater
@ -17,15 +16,14 @@ import com.futo.platformplayer.api.media.structures.*
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.states.StateMeta
import com.futo.platformplayer.states.StatePlayer
import com.futo.platformplayer.states.StatePlaylists
import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.PreviewContentListAdapter
import com.futo.platformplayer.views.adapters.feedtypes.PreviewContentListAdapter
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
import com.futo.platformplayer.views.adapters.InsertedViewHolder
import com.futo.platformplayer.views.adapters.PreviewNestedVideoViewHolder
import com.futo.platformplayer.views.adapters.PreviewVideoViewHolder
import com.futo.platformplayer.views.adapters.feedtypes.PreviewNestedVideoViewHolder
import com.futo.platformplayer.views.adapters.feedtypes.PreviewVideoViewHolder
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuItem
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
import kotlin.math.floor
@ -66,6 +64,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
private fun attachAdapterEvents(adapter: PreviewContentListAdapter) {
adapter.onContentUrlClicked.subscribe(this, this@ContentFeedView::onContentUrlClicked);
adapter.onUrlClicked.subscribe(this, this@ContentFeedView::onUrlClicked);
adapter.onContentClicked.subscribe(this) { content, time ->
this@ContentFeedView.onContentClicked(content, time);
};
@ -132,6 +131,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
private fun detachAdapterEvents() {
val adapter = recyclerData.adapter as PreviewContentListAdapter? ?: return;
adapter.onContentUrlClicked.remove(this);
adapter.onUrlClicked.remove(this);
adapter.onContentClicked.remove(this);
adapter.onChannelClicked.remove(this);
adapter.onAddToClicked.remove(this);
@ -191,6 +191,9 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
else -> {};
}
}
protected open fun onUrlClicked(url: String) {
fragment.navigate<BrowserFragment>(url);
}
private fun playPreview() {
if(feedStyle == FeedStyle.THUMBNAIL)

View file

@ -20,7 +20,6 @@ import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.futo.platformplayer.R
import com.futo.platformplayer.UIDialogs
import com.futo.platformplayer.UISlideOverlays
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.models.Thumbnails
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
@ -46,7 +45,7 @@ import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.platform.PlatformIndicator
import com.futo.platformplayer.views.subscriptions.SubscribeButton
import com.futo.platformplayer.views.others.Toggle
import com.futo.platformplayer.views.adapters.PreviewPostView
import com.futo.platformplayer.views.adapters.feedtypes.PreviewPostView
import com.futo.platformplayer.views.overlays.RepliesOverlay
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
import com.futo.polycentric.core.ApiMethods

View file

@ -280,7 +280,7 @@ class SubscriptionsFeedFragment : MainFragment() {
override fun filterResults(results: List<IPlatformContent>): List<IPlatformContent> {
val nowSoon = OffsetDateTime.now().plusMinutes(5);
return results.filter {
val allowedContentType = _filterSettings.allowContentTypes.contains(if(it.contentType == ContentType.NESTED_VIDEO) ContentType.MEDIA else it.contentType);
val allowedContentType = _filterSettings.allowContentTypes.contains(if(it.contentType == ContentType.NESTED_VIDEO || it.contentType == ContentType.LOCKED) ContentType.MEDIA else it.contentType);
if(it.datetime?.isAfter(nowSoon) == true) {
if(!_filterSettings.allowPlanned)

View file

@ -1087,7 +1087,7 @@ class VideoDetailView : ConstraintLayout {
_player.setMetadata(video.name, video.author.name);
_toggleCommentType.setValue(false, false);
_toggleCommentType.setValue(Settings.instance.comments.defaultCommentSection == 1, false);
updateCommentType(true);
//UI

View file

@ -15,6 +15,7 @@ class ChannelViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifec
private val _cache: Array<Fragment?> = arrayOfNulls(4);
val onContentUrlClicked = Event2<String, ContentType>();
val onUrlClicked = Event1<String>();
val onContentClicked = Event2<IPlatformContent, Long>();
val onChannelClicked = Event1<PlatformAuthorLink>();
val onAddToClicked = Event1<IPlatformContent>();
@ -50,6 +51,7 @@ class ChannelViewPagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifec
0 -> ChannelContentsFragment.newInstance().apply {
onContentClicked.subscribe(this@ChannelViewPagerAdapter.onContentClicked::emit);
onContentUrlClicked.subscribe(this@ChannelViewPagerAdapter.onContentUrlClicked::emit);
onUrlClicked.subscribe(this@ChannelViewPagerAdapter.onUrlClicked::emit);
onChannelClicked.subscribe(this@ChannelViewPagerAdapter.onChannelClicked::emit);
onAddToClicked.subscribe(this@ChannelViewPagerAdapter.onAddToClicked::emit);
onAddToQueueClicked.subscribe(this@ChannelViewPagerAdapter.onAddToQueueClicked::emit);

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.content.Context
import android.util.Log
@ -18,6 +18,9 @@ import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StatePlatform
import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.EmptyPreviewViewHolder
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewViewHolder> {
private var _initialPlay = true;
@ -27,6 +30,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
private val _feedStyle : FeedStyle;
private var _paused: Boolean = false;
val onUrlClicked = Event1<String>();
val onContentUrlClicked = Event2<String, ContentType>();
val onContentClicked = Event2<IPlatformContent, Long>();
val onChannelClicked = Event1<PlatformAuthorLink>();
@ -72,6 +76,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
ContentType.POST -> createPostViewHolder(viewGroup);
ContentType.PLAYLIST -> createPlaylistViewHolder(viewGroup);
ContentType.NESTED_VIDEO -> createNestedViewHolder(viewGroup);
ContentType.LOCKED -> createLockedViewHolder(viewGroup);
else -> EmptyPreviewViewHolder(viewGroup)
}
}
@ -87,6 +92,9 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
this.onAddToClicked.subscribe(this@PreviewContentListAdapter.onAddToClicked::emit);
this.onAddToQueueClicked.subscribe(this@PreviewContentListAdapter.onAddToQueueClicked::emit);
};
private fun createLockedViewHolder(viewGroup: ViewGroup): PreviewLockedViewHolder = PreviewLockedViewHolder(viewGroup, _feedStyle).apply {
this.onLockedUrlClicked.subscribe(this@PreviewContentListAdapter.onUrlClicked::emit);
};
private fun createPlaceholderViewHolder(viewGroup: ViewGroup): PreviewPlaceholderViewHolder
= PreviewPlaceholderViewHolder(viewGroup, _feedStyle);
private fun createVideoPreviewViewHolder(viewGroup: ViewGroup): PreviewVideoViewHolder = PreviewVideoViewHolder(viewGroup, _feedStyle, _exoPlayer).apply {
@ -143,6 +151,7 @@ class PreviewContentListAdapter : InsertedViewAdapterWithLoader<ContentPreviewVi
fun release() {
_taskLoadContent.dispose();
onContentUrlClicked.clear();
onUrlClicked.clear();
onContentClicked.clear();
onChannelClicked.clear();
onAddToClicked.clear();

View file

@ -0,0 +1,134 @@
package com.futo.platformplayer.views.adapters.feedtypes
import android.animation.ObjectAnimator
import android.content.Context
import android.content.res.Resources
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import com.bumptech.glide.Glide
import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.PlatformID
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.locked.IPlatformLockedContent
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.constructs.TaskHandler
import com.futo.platformplayer.images.GlideHelper.Companion.crossfade
import com.futo.platformplayer.images.GlideHelper.Companion.loadThumbnails
import com.futo.platformplayer.logging.Logger
import com.futo.platformplayer.polycentric.PolycentricCache
import com.futo.platformplayer.states.StateApp
import com.futo.platformplayer.states.StateDownloads
import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.platform.PlatformIndicator
import com.futo.platformplayer.views.video.FutoThumbnailPlayer
import com.futo.polycentric.core.toURLInfoSystemLinkUrl
import com.google.android.material.imageview.ShapeableImageView
class PreviewLockedView : LinearLayout {
protected val _feedStyle : FeedStyle;
private val _textChannelName: TextView;
private val _textVideoName: TextView;
//private val _imageNeoPassChannel: ImageView;
private val _imageChannelThumbnail: ImageView;
private val _imageVideoThumbnail: ImageView;
private val _platformIndicator: PlatformIndicator;
private val _textLockedDescription: TextView;
//private val _textBrowserOpen: TextView;
private val _textLockedUrl: TextView;
private val _textVideoMetadata: TextView;
val onLockedUrlClicked = Event1<String>();
constructor(context: Context, feedStyle : FeedStyle) : super(context) {
inflate(feedStyle);
_feedStyle = feedStyle;
_textVideoName = findViewById(R.id.text_video_name);
_textChannelName = findViewById(R.id.text_channel_name);
//_imageNeoPassChannel = findViewById(R.id.image_neopass_channel);
_imageChannelThumbnail = findViewById(R.id.image_channel_thumbnail);
_imageVideoThumbnail = findViewById(R.id.image_video_thumbnail);
_platformIndicator = findViewById(R.id.thumbnail_platform)
_textLockedDescription = findViewById(R.id.text_locked_description);
//_textBrowserOpen = findViewById(R.id.text_browser_open);
_textLockedUrl = findViewById(R.id.text_locked_url);
_textVideoMetadata = findViewById(R.id.text_video_metadata);
setOnClickListener {
if(!_textLockedUrl.text.isNullOrEmpty())
onLockedUrlClicked.emit(_textLockedUrl.text.toString());
}
}
protected open fun inflate(feedStyle: FeedStyle) {
inflate(context, when(feedStyle) {
FeedStyle.PREVIEW -> R.layout.list_locked_preview
else -> R.layout.list_locked_thumbnail
}, this)
}
open fun bind(content: IPlatformContent) {
_textVideoName.text = content.name;
_textChannelName.text = content.author.name;
_platformIndicator.setPlatformFromClientID(content.id.pluginId);
if(content is IPlatformLockedContent) {
_imageVideoThumbnail.loadThumbnails(content.contentThumbnails, false) {
it.placeholder(R.drawable.placeholder_video_thumbnail)
.into(_imageVideoThumbnail);
};
Glide.with(_imageChannelThumbnail)
.load(content.author.thumbnail)
.placeholder(R.drawable.placeholder_channel_thumbnail)
.into(_imageChannelThumbnail);
_textLockedDescription.text = content.lockDescription ?: "";
_textLockedUrl.text = content.unlockUrl ?: "";
}
else {
_imageChannelThumbnail.setImageResource(0);
_imageVideoThumbnail.setImageResource(0);
_textLockedDescription.text = "";
_textLockedUrl.text = "";
}
if(_textLockedUrl.text.isNullOrEmpty()) {
_textLockedUrl.visibility = GONE;
_textVideoMetadata.text = "";
}
else {
_textLockedUrl.visibility = VISIBLE;
_textVideoMetadata.text = "Tap to open in browser";
}
}
open fun preview(video: IPlatformContentDetails?, paused: Boolean) {
}
companion object {
private val TAG = "PreviewLockedView"
}
}

View file

@ -0,0 +1,46 @@
package com.futo.platformplayer.views.adapters.feedtypes
import android.content.Context
import android.graphics.drawable.Animatable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.contents.PlatformContentPlaceholder
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.platform.PlatformIndicator
class PreviewLockedViewHolder : ContentPreviewViewHolder {
override var content: IPlatformContent? = null;
private val view: PreviewLockedView get() = itemView as PreviewLockedView;
val onLockedUrlClicked = Event1<String>();
val context: Context;
constructor(viewGroup: ViewGroup, feedStyle: FeedStyle) : super(PreviewLockedView(viewGroup.context, feedStyle)) {
context = itemView.context;
view.onLockedUrlClicked.subscribe(onLockedUrlClicked::emit);
}
override fun bind(content: IPlatformContent) = view.bind(content);
override fun preview(video: IPlatformContentDetails?, paused: Boolean) { }
override fun stopPreview() { }
override fun pausePreview() { }
override fun resumePreview() { }
companion object {
private val TAG = "PlaceholderPreviewViewHolder"
}
}

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.content.Context
import android.view.View

View file

@ -1,9 +1,6 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.FrameLayout
import com.futo.platformplayer.*
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
import com.futo.platformplayer.api.media.models.contents.ContentType
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
@ -13,6 +10,7 @@ import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
class PreviewNestedVideoViewHolder : ContentPreviewViewHolder {
@ -25,7 +23,9 @@ class PreviewNestedVideoViewHolder : ContentPreviewViewHolder {
override val content: IPlatformContent? get() = view.content;
private val view: PreviewNestedVideoView get() = itemView as PreviewNestedVideoView;
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(PreviewNestedVideoView(viewGroup.context, feedStyle, exoPlayer)) {
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(
PreviewNestedVideoView(viewGroup.context, feedStyle, exoPlayer)
) {
view.onContentUrlClicked.subscribe(onContentUrlClicked::emit);
view.onVideoClicked.subscribe(onVideoClicked::emit);
view.onChannelClicked.subscribe(onChannelClicked::emit);

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.content.Context
import android.graphics.drawable.Animatable
@ -12,6 +12,7 @@ import com.futo.platformplayer.api.media.models.contents.IPlatformContent
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.contents.PlatformContentPlaceholder
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.platform.PlatformIndicator

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.view.ViewGroup
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
@ -7,6 +7,8 @@ import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.api.media.models.playlists.IPlatformPlaylist
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
import com.futo.platformplayer.views.adapters.PlaylistView
class PreviewPlaylistViewHolder : ContentPreviewViewHolder {

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.animation.ObjectAnimator
import android.content.Context

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.view.ViewGroup
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
@ -7,6 +7,7 @@ import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
class PreviewPostViewHolder : ContentPreviewViewHolder {
@ -18,7 +19,9 @@ class PreviewPostViewHolder : ContentPreviewViewHolder {
private val view: PreviewPostView get() = itemView as PreviewPostView;
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(PreviewPostView(viewGroup.context, feedStyle)) {
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(
PreviewPostView(viewGroup.context, feedStyle)
) {
view.onContentClicked.subscribe(onContentClicked::emit);
view.onChannelClicked.subscribe(onChannelClicked::emit);
}

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.animation.ObjectAnimator
import android.content.Context

View file

@ -1,4 +1,4 @@
package com.futo.platformplayer.views.adapters
package com.futo.platformplayer.views.adapters.feedtypes
import android.view.ViewGroup
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
@ -9,6 +9,7 @@ import com.futo.platformplayer.constructs.Event1
import com.futo.platformplayer.constructs.Event2
import com.futo.platformplayer.video.PlayerManager
import com.futo.platformplayer.views.FeedStyle
import com.futo.platformplayer.views.adapters.ContentPreviewViewHolder
class PreviewVideoViewHolder : ContentPreviewViewHolder {
@ -26,7 +27,9 @@ class PreviewVideoViewHolder : ContentPreviewViewHolder {
private val view: PreviewVideoView get() = itemView as PreviewVideoView;
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(PreviewVideoView(viewGroup.context, feedStyle, exoPlayer)) {
constructor(viewGroup: ViewGroup, feedStyle : FeedStyle, exoPlayer: PlayerManager? = null): super(
PreviewVideoView(viewGroup.context, feedStyle, exoPlayer)
) {
view.onVideoClicked.subscribe(onVideoClicked::emit);
view.onChannelClicked.subscribe(onChannelClicked::emit);
view.onAddToClicked.subscribe(onAddToClicked::emit);

View file

@ -0,0 +1,333 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintDimensionRatio="H,16:13">
<FrameLayout
android:id="@+id/player_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintDimensionRatio="H,16:9">
<ImageView
android:id="@+id/image_video_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:contentDescription="@string/thumbnail"
android:scaleType="centerCrop"
android:layout_marginBottom="6dp"
tools:srcCompat="@drawable/placeholder_video_thumbnail" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--
<com.futo.platformplayer.views.platform.PlatformIndicator
android:id="@+id/thumbnail_platform_nested"
android:layout_width="25dp"
android:layout_height="25dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_margin="5dp"
android:scaleType="centerInside"
tools:src="@drawable/ic_peertube"/> -->
<LinearLayout
android:id="@+id/thumbnail_live_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="13dp"
android:paddingTop="0dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="@drawable/background_thumbnail_live"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent">
<TextView
android:id="@+id/thumbnail_live"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:textColor="#FFFFFF"
android:textSize="12dp"
android:text="@string/live"
android:layout_gravity="center"
android:textStyle="normal" />
</LinearLayout>
<LinearLayout
android:id="@+id/thumbnail_duration_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="13dp"
android:paddingTop="0dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="@drawable/background_thumbnail_duration"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent">
<TextView
android:id="@+id/thumbnail_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:textColor="#FFFFFF"
android:textSize="12dp"
tools:text="0:00"
android:layout_gravity="center"
android:textStyle="normal" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/container_loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="6dp"
android:background="#DD000000"
android:visibility="gone"
android:orientation="vertical">
</LinearLayout>
<LinearLayout
android:id="@+id/container_locked"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="6dp"
android:background="#DD000000"
android:visibility="visible"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#AAAA"
android:layout_marginTop="50dp"
android:textSize="12dp"
android:layout_weight="1"
android:text="@string/locked_content_description"
android:textAlignment="center" />
<TextView
android:id="@+id/text_locked_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:textSize="16dp"
android:layout_weight="1"
android:text="Lorem ipsum something something, and something more perhaps"
android:textAlignment="center" />
<TextView
android:id="@+id/text_browser_open"
android:textColor="#AAAA"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="13dp"
android:text="@string/tap_to_open_in_browser"
android:textAlignment="center" />
<TextView
android:id="@+id/text_locked_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:maxLines="1"
android:ellipsize="end"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:textSize="12dp"
android:textColor="#828EFF"
android:layout_weight="1"
android:text="@string/unknown"
android:textAlignment="center" />
</LinearLayout>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="-6dp"
app:layout_constraintTop_toBottomOf="@id/player_container"
app:layout_constraintBottom_toBottomOf="parent"
android:orientation="vertical"
android:gravity="center_vertical">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:gravity="top"
android:orientation="horizontal"
android:layout_gravity="center_vertical"
android:paddingBottom="5dp">
<com.futo.platformplayer.views.others.CreatorThumbnail
android:id="@+id/creator_thumbnail"
android:layout_width="32dp"
android:layout_height="32dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/creator_thumbnail"
app:layout_constraintLeft_toRightOf="@id/creator_thumbnail"
app:layout_constraintRight_toLeftOf="@id/container_info"
android:orientation="vertical"
android:paddingStart="10dp">
<TextView
android:id="@+id/text_video_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:layout_marginTop="-3dp"
android:textSize="14dp"
android:textColor="@color/white"
android:fontFamily="@font/inter_regular"
tools:text="I Thought FSD is Terrible in SNOW | 8 inch SNOW | FSD Beta 10.69.2.4"
android:maxLines="2" />
<TextView
android:id="@+id/text_channel_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:maxLines="1"
android:textSize="12dp"
android:textColor="@color/gray_e0"
android:fontFamily="@font/inter_extra_light"
tools:text="Two Minute Papers" />
<TextView
android:id="@+id/text_video_metadata"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:gravity="center_vertical"
android:textSize="12dp"
android:textColor="@color/gray_e0"
android:fontFamily="@font/inter_extra_light"
tools:text="57K views • 1 day ago" />
</LinearLayout>
<LinearLayout
android:id="@+id/container_info"
android:layout_width="wrap_content"
android:layout_height="30dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginEnd="6dp"
android:paddingLeft="10dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<!--
<FrameLayout android:id="@+id/layout_downloaded"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="8dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
app:srcCompat="@drawable/download_for_offline" />
</FrameLayout> -->
<com.futo.platformplayer.views.platform.PlatformIndicator
android:id="@+id/thumbnail_platform"
android:layout_width="25dp"
android:layout_height="25dp"
android:scaleType="centerInside"
tools:src="@drawable/ic_peertube"/>
</LinearLayout>
<LinearLayout
android:id="@+id/container_buttons"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:orientation="horizontal"
android:paddingEnd="6dp">
<!--
<ImageButton
android:id="@+id/button_add_to_queue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="1dp"
android:paddingTop="7dp"
android:paddingStart="6dp"
android:paddingEnd="5dp"
android:paddingBottom="3dp"
app:srcCompat="@drawable/ic_queue_16dp"
android:background="@drawable/edit_text_background"
android:contentDescription="@string/add_to_queue" />
<LinearLayout
android:id="@+id/button_add_to"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/edit_text_background"
android:layout_marginStart="4dp"
android:gravity="center_vertical"
android:padding="4dp">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
app:srcCompat="@drawable/ic_add_white_8dp"
android:layout_marginStart="4dp"
android:contentDescription="@string/options" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/options"
android:background="@color/transparent"
android:textSize="12dp"
android:textColor="@color/white"
android:fontFamily="@font/inter_light"
android:layout_marginEnd="4dp"/>
</LinearLayout> -->
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,317 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="115dp"
android:orientation="vertical">
<LinearLayout
android:id="@+id/item_video"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp">
<FrameLayout
android:id="@+id/player_container"
android:layout_width="178dp"
android:layout_height="100dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image_video_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="@string/thumbnail"
app:shapeAppearanceOverlay="@style/roundedCorners_4dp"
app:srcCompat="@drawable/placeholder_video_thumbnail"
android:background="@drawable/video_thumbnail_outline" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--
<LinearLayout
android:id="@+id/thumbnail_live_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="4dp"
android:paddingTop="0dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="@drawable/background_thumbnail_live">
<TextView
android:id="@+id/thumbnail_live"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:textColor="#FFFFFF"
android:textSize="12dp"
android:text="@string/live"
android:layout_gravity="center"
android:textStyle="normal" />
</LinearLayout> -->
<!--
<LinearLayout
android:id="@+id/thumbnail_duration_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="4dp"
android:paddingTop="0dp"
android:gravity="center_vertical"
android:orientation="horizontal"
android:background="@drawable/background_thumbnail_duration">
<TextView
android:id="@+id/thumbnail_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:includeFontPadding="false"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:textColor="#FFFFFF"
android:textSize="12dp"
tools:text="0:00"
android:layout_gravity="center"
android:textStyle="normal" />
</LinearLayout> -->
<!--
<FrameLayout android:id="@+id/layout_downloaded"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:background="@drawable/background_pill_black"
android:layout_marginTop="2dp"
android:layout_marginEnd="2dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
app:srcCompat="@drawable/download_for_offline" />
</FrameLayout> -->
</RelativeLayout>
<LinearLayout
android:id="@+id/container_loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BB000000"
android:visibility="gone"
android:orientation="vertical" />
<LinearLayout
android:id="@+id/container_locked"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#BB000000"
android:visibility="visible"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="10dp"
android:textSize="10dp"
android:text="@string/locked_content_description"
android:textAlignment="center" />
<TextView
android:id="@+id/text_locked_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12dp"
android:maxLines="3"
android:ellipsize="end"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:layout_weight="1"
android:text="Lorem ipsum something something, and something more perhaps"
android:textAlignment="center" />
<!--
<TextView
android:id="@+id/text_browser_open"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="10dp"
android:layout_weight="1"
android:text="@string/tap_to_open_in_browser"
android:textAlignment="center" /> -->
<TextView
android:id="@+id/text_locked_url"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
android:maxLines="1"
android:ellipsize="end"
android:textColor="#828EFF"
android:layout_weight="1"
android:textSize="10dp"
android:text="@string/unknown"
android:textAlignment="center" />
</LinearLayout>
</FrameLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="6dp"
android:layout_marginEnd="6dp">
<!--
<ImageButton
android:id="@+id/button_add_to_queue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="1dp"
android:paddingTop="7dp"
android:paddingStart="6dp"
android:paddingEnd="5dp"
android:paddingBottom="3dp"
app:srcCompat="@drawable/ic_queue_16dp"
android:background="@drawable/edit_text_background"
android:contentDescription="@string/add_to_queue"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<LinearLayout
android:id="@+id/button_add_to"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@drawable/edit_text_background"
android:layout_marginStart="4dp"
android:gravity="center_vertical"
android:padding="4dp"
app:layout_constraintLeft_toRightOf="@id/button_add_to_queue"
app:layout_constraintBottom_toBottomOf="parent">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
app:srcCompat="@drawable/ic_add_white_8dp"
android:layout_marginStart="4dp"
android:contentDescription="@string/options" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/options"
android:background="@color/transparent"
android:textSize="12dp"
android:textColor="@color/white"
android:fontFamily="@font/inter_light"
android:layout_marginEnd="4dp"/>
</LinearLayout> -->
<TextView
android:id="@+id/text_video_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:textSize="13dp"
android:textColor="@color/white"
android:fontFamily="@font/inter_light"
tools:text="Legendary grant recipient: Marvin Wißfeld of MicroG Very loong title"
android:maxLines="2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<ImageView
android:id="@+id/image_channel_thumbnail"
android:layout_width="28dp"
android:layout_height="28dp"
android:background="@drawable/rounded_outline"
android:contentDescription="@string/channel_image"
tools:src="@drawable/placeholder_channel_thumbnail"
android:clipToOutline="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_video_name" />
<TextView
android:id="@+id/text_channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
android:maxLines="1"
android:ellipsize="end"
android:textSize="10dp"
android:textColor="@color/gray_e0"
android:fontFamily="@font/inter_extra_light"
tools:text="Two Minute Papers"
app:layout_constrainedWidth="true"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@id/image_channel_thumbnail"
app:layout_constraintRight_toLeftOf="@id/image_neopass_channel"
app:layout_constraintTop_toBottomOf="@id/text_video_name"
android:layout_marginStart="4dp" />
<ImageView
android:id="@+id/image_neopass_channel"
android:layout_width="10dp"
android:layout_height="10dp"
android:contentDescription="@string/neopass_channel"
app:srcCompat="@drawable/neopass"
app:layout_constraintLeft_toRightOf="@id/text_channel_name"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/text_channel_name"
app:layout_constraintBottom_toBottomOf="@id/text_channel_name"
android:layout_marginStart="4dp"
android:visibility="gone"/>
<TextView
android:id="@+id/text_video_metadata"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:maxLines="1"
android:gravity="center_vertical"
android:textSize="10dp"
android:textColor="@color/gray_e0"
android:fontFamily="@font/inter_extra_light"
tools:text="57K views • 1 day ago"
app:layout_constraintLeft_toRightOf="@id/image_channel_thumbnail"
app:layout_constraintTop_toBottomOf="@id/text_channel_name"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginStart="4dp"/>
<com.futo.platformplayer.views.platform.PlatformIndicator
android:id="@+id/thumbnail_platform"
android:layout_width="20dp"
android:layout_height="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_margin="4dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</LinearLayout>

View file

@ -80,6 +80,7 @@
<string name="developer">Developer</string>
<string name="remove_historical_suggestion">Remove historical suggestion</string>
<string name="comments">Comments</string>
<string name="comments_description">The comment section underneath content</string>
<string name="merchandise">Merchandise</string>
<string name="reached_the_end_of_the_playlist">Reached the end of the playlist</string>
<string name="the_playlist_will_restart_after_the_video_is_finished">The playlist will restart after the video is finished</string>
@ -219,6 +220,7 @@
<string name="construction">CONSTRUCTION</string>
<string name="disable">Disable</string>
<string name="the_following_content_cannot_be_opened_in_grayjay_due_to_a_missing_plugin">The following content cannot be opened in Grayjay due to a missing plugin.</string>
<string name="locked_content_description">This content is locked</string>
<string name="unknown">Unknown</string>
<string name="tap_to_open_in_browser">Tap to open in browser</string>
<string name="missing_plugin">Missing Plugin</string>
@ -349,6 +351,7 @@
<string name="preferred_metered_quality">Preferred Metered Quality</string>
<string name="preferred_preview_quality">Preferred Preview Quality</string>
<string name="primary_language">Primary Language</string>
<string name="default_comment_section">Default Comment Section</string>
<string name="reinstall_embedded_plugins">Reinstall Embedded Plugins</string>
<string name="remove_cached_version">Remove Cached Version</string>
<string name="remove_the_last_downloaded_version">Remove the last downloaded version</string>
@ -789,6 +792,10 @@
<item>60</item>
<item>120</item>
</string-array>
<string-array name="comment_sections">
<item>Polycentric</item>
<item>Platform</item>
</string-array>
<string-array name="audio_languages">
<item>English</item>
<item>Spanish</item>

@ -1 +1 @@
Subproject commit 9e26b7032e64ed03315a8e75d2174cb4253030d1
Subproject commit 339b44e9f00521ab4cfe755a343fd9e6e5338d04