mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-02 15:44:26 +02:00
Support for per-comment lazy loading for Polycentric
This commit is contained in:
parent
da27517fcf
commit
b45d4c0557
@ -0,0 +1,63 @@
|
|||||||
|
package com.futo.platformplayer.api.media.models.comments
|
||||||
|
|
||||||
|
import com.futo.platformplayer.api.media.IPlatformClient
|
||||||
|
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||||
|
import com.futo.platformplayer.api.media.models.ratings.IRating
|
||||||
|
import com.futo.platformplayer.api.media.models.ratings.RatingLikes
|
||||||
|
import com.futo.platformplayer.api.media.models.ratings.RatingType
|
||||||
|
import com.futo.platformplayer.api.media.structures.IPager
|
||||||
|
import com.futo.platformplayer.logging.Logger
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
|
class LazyComment: IPlatformComment {
|
||||||
|
private var _commentDeferred: Deferred<IPlatformComment>;
|
||||||
|
private var _commentLoaded: IPlatformComment? = null;
|
||||||
|
private var _commentException: Throwable? = null;
|
||||||
|
|
||||||
|
override val contextUrl: String
|
||||||
|
get() = _commentLoaded?.contextUrl ?: "";
|
||||||
|
override val author: PlatformAuthorLink
|
||||||
|
get() = _commentLoaded?.author ?: PlatformAuthorLink.UNKNOWN;
|
||||||
|
override val message: String
|
||||||
|
get() = _commentLoaded?.message ?: "";
|
||||||
|
override val rating: IRating
|
||||||
|
get() = _commentLoaded?.rating ?: RatingLikes(0);
|
||||||
|
override val date: OffsetDateTime?
|
||||||
|
get() = _commentLoaded?.date ?: OffsetDateTime.MIN;
|
||||||
|
override val replyCount: Int?
|
||||||
|
get() = _commentLoaded?.replyCount ?: 0;
|
||||||
|
|
||||||
|
val isAvailable: Boolean get() = _commentLoaded != null;
|
||||||
|
|
||||||
|
private var _uiHandler: ((LazyComment)->Unit)? = null;
|
||||||
|
|
||||||
|
constructor(commentDeferred: Deferred<IPlatformComment>) {
|
||||||
|
_commentDeferred = commentDeferred;
|
||||||
|
_commentDeferred.invokeOnCompletion {
|
||||||
|
if(it == null) {
|
||||||
|
_commentLoaded = commentDeferred.getCompleted();
|
||||||
|
Logger.i("LazyComment", "Resolved comment");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_commentException = it;
|
||||||
|
Logger.e("LazyComment", "Resolving comment failed: ${it.message}", it);
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiHandler?.invoke(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getUnderlyingComment(): IPlatformComment? {
|
||||||
|
return _commentLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setUIHandler(handler: (LazyComment)->Unit){
|
||||||
|
_uiHandler = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getReplies(client: IPlatformClient): IPager<IPlatformComment>? {
|
||||||
|
return _commentLoaded?.getReplies(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -10,6 +10,7 @@ import com.futo.platformplayer.activities.PolycentricHomeActivity
|
|||||||
import com.futo.platformplayer.api.media.PlatformID
|
import com.futo.platformplayer.api.media.PlatformID
|
||||||
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
|
import com.futo.platformplayer.api.media.models.comments.LazyComment
|
||||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
|
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
|
||||||
@ -46,6 +47,7 @@ import com.google.protobuf.ByteString
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.asCoroutineDispatcher
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import userpackage.Protocol
|
import userpackage.Protocol
|
||||||
@ -53,6 +55,7 @@ import userpackage.Protocol.Reference
|
|||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import java.time.ZoneOffset
|
import java.time.ZoneOffset
|
||||||
|
import java.util.concurrent.ForkJoinPool
|
||||||
|
|
||||||
class StatePolycentric {
|
class StatePolycentric {
|
||||||
private data class LikeDislikeEntry(val unixMilliseconds: Long, val hasLiked: Boolean, val hasDisliked: Boolean);
|
private data class LikeDislikeEntry(val unixMilliseconds: Long, val hasLiked: Boolean, val hasDisliked: Boolean);
|
||||||
@ -63,6 +66,9 @@ class StatePolycentric {
|
|||||||
private var _transientEnabled = true
|
private var _transientEnabled = true
|
||||||
val enabled get() = _transientEnabled && Settings.instance.other.polycentricEnabled
|
val enabled get() = _transientEnabled && Settings.instance.other.polycentricEnabled
|
||||||
|
|
||||||
|
private val _commentPool = ForkJoinPool(2);
|
||||||
|
private val _commentPoolDispatcher = _commentPool.asCoroutineDispatcher();
|
||||||
|
|
||||||
fun load(context: Context) {
|
fun load(context: Context) {
|
||||||
if (!enabled) {
|
if (!enabled) {
|
||||||
return
|
return
|
||||||
@ -510,7 +516,7 @@ class StatePolycentric {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun mapQueryReferences(contextUrl: String, response: Protocol.QueryReferencesResponse): List<PolycentricPlatformComment> {
|
private suspend fun mapQueryReferences(contextUrl: String, response: Protocol.QueryReferencesResponse): List<IPlatformComment> {
|
||||||
return response.itemsList.mapNotNull {
|
return response.itemsList.mapNotNull {
|
||||||
val sev = SignedEvent.fromProto(it.event);
|
val sev = SignedEvent.fromProto(it.event);
|
||||||
val ev = sev.event;
|
val ev = sev.event;
|
||||||
@ -524,49 +530,53 @@ class StatePolycentric {
|
|||||||
val dislikes = it.countsList[1];
|
val dislikes = it.countsList[1];
|
||||||
val replies = it.countsList[2];
|
val replies = it.countsList[2];
|
||||||
|
|
||||||
val profileEvents = ApiMethods.getQueryLatest(
|
val scope = StateApp.instance.scopeOrNull ?: return@mapNotNull null;
|
||||||
PolycentricCache.SERVER,
|
return@mapNotNull LazyComment(scope.async(_commentPoolDispatcher){
|
||||||
ev.system.toProto(),
|
Logger.i(TAG, "Fetching comment data for [" + ev.system.key.toBase64() + "]");
|
||||||
listOf(
|
val profileEvents = ApiMethods.getQueryLatest(
|
||||||
ContentType.AVATAR.value,
|
PolycentricCache.SERVER,
|
||||||
ContentType.USERNAME.value
|
ev.system.toProto(),
|
||||||
)
|
listOf(
|
||||||
).eventsList.map { e -> SignedEvent.fromProto(e) }.groupBy { e -> e.event.contentType }
|
ContentType.AVATAR.value,
|
||||||
.map { (_, events) -> events.maxBy { x -> x.event.unixMilliseconds ?: 0 } };
|
ContentType.USERNAME.value
|
||||||
|
)
|
||||||
|
).eventsList.map { e -> SignedEvent.fromProto(e) }.groupBy { e -> e.event.contentType }
|
||||||
|
.map { (_, events) -> events.maxBy { x -> x.event.unixMilliseconds ?: 0 } };
|
||||||
|
|
||||||
val nameEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.USERNAME.value };
|
val nameEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.USERNAME.value };
|
||||||
val avatarEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.AVATAR.value };
|
val avatarEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.AVATAR.value };
|
||||||
val imageBundle = if (avatarEvent != null) {
|
val imageBundle = if (avatarEvent != null) {
|
||||||
val lwwElementValue = avatarEvent.event.lwwElement?.value;
|
val lwwElementValue = avatarEvent.event.lwwElement?.value;
|
||||||
if (lwwElementValue != null) {
|
if (lwwElementValue != null) {
|
||||||
Protocol.ImageBundle.parseFrom(lwwElementValue)
|
Protocol.ImageBundle.parseFrom(lwwElementValue)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
|
|
||||||
val unixMilliseconds = ev.unixMilliseconds
|
val unixMilliseconds = ev.unixMilliseconds
|
||||||
//TODO: Don't use single hardcoded sderver here
|
//TODO: Don't use single hardcoded sderver here
|
||||||
val systemLinkUrl = ev.system.systemToURLInfoSystemLinkUrl(listOf(PolycentricCache.SERVER));
|
val systemLinkUrl = ev.system.systemToURLInfoSystemLinkUrl(listOf(PolycentricCache.SERVER));
|
||||||
val dp_25 = 25.dp(StateApp.instance.context.resources)
|
val dp_25 = 25.dp(StateApp.instance.context.resources)
|
||||||
return@mapNotNull PolycentricPlatformComment(
|
return@async PolycentricPlatformComment(
|
||||||
contextUrl = contextUrl,
|
contextUrl = contextUrl,
|
||||||
author = PlatformAuthorLink(
|
author = PlatformAuthorLink(
|
||||||
id = PlatformID("polycentric", systemLinkUrl, null, ClaimType.POLYCENTRIC.value.toInt()),
|
id = PlatformID("polycentric", systemLinkUrl, null, ClaimType.POLYCENTRIC.value.toInt()),
|
||||||
name = nameEvent?.event?.lwwElement?.value?.decodeToString() ?: "Unknown",
|
name = nameEvent?.event?.lwwElement?.value?.decodeToString() ?: "Unknown",
|
||||||
url = systemLinkUrl,
|
url = systemLinkUrl,
|
||||||
thumbnail = imageBundle?.selectBestImage(dp_25 * dp_25)?.let { img -> img.toURLInfoSystemLinkUrl(ev.system.toProto(), img.process, listOf(PolycentricCache.SERVER)) },
|
thumbnail = imageBundle?.selectBestImage(dp_25 * dp_25)?.let { img -> img.toURLInfoSystemLinkUrl(ev.system.toProto(), img.process, listOf(PolycentricCache.SERVER)) },
|
||||||
subscribers = null
|
subscribers = null
|
||||||
),
|
),
|
||||||
msg = if (post.content.count() > PolycentricPlatformComment.MAX_COMMENT_SIZE) post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE) else post.content,
|
msg = if (post.content.count() > PolycentricPlatformComment.MAX_COMMENT_SIZE) post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE) else post.content,
|
||||||
rating = RatingLikeDislikes(likes, dislikes),
|
rating = RatingLikeDislikes(likes, dislikes),
|
||||||
date = if (unixMilliseconds != null) Instant.ofEpochMilli(unixMilliseconds).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
|
date = if (unixMilliseconds != null) Instant.ofEpochMilli(unixMilliseconds).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
|
||||||
replyCount = replies.toInt(),
|
replyCount = replies.toInt(),
|
||||||
eventPointer = sev.toPointer(),
|
eventPointer = sev.toPointer(),
|
||||||
parentReference = sev.event.references.getOrNull(0)
|
parentReference = sev.event.references.getOrNull(0)
|
||||||
);
|
);
|
||||||
|
});
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
return@mapNotNull null;
|
return@mapNotNull null;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
|||||||
import com.futo.platformplayer.R
|
import com.futo.platformplayer.R
|
||||||
import com.futo.platformplayer.Settings
|
import com.futo.platformplayer.Settings
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
|
import com.futo.platformplayer.api.media.models.comments.LazyComment
|
||||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
|
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
|
||||||
import com.futo.platformplayer.api.media.models.ratings.RatingLikes
|
import com.futo.platformplayer.api.media.models.ratings.RatingLikes
|
||||||
@ -24,6 +25,7 @@ import com.futo.platformplayer.states.StateApp
|
|||||||
import com.futo.platformplayer.states.StatePolycentric
|
import com.futo.platformplayer.states.StatePolycentric
|
||||||
import com.futo.platformplayer.toHumanNowDiffString
|
import com.futo.platformplayer.toHumanNowDiffString
|
||||||
import com.futo.platformplayer.toHumanNumber
|
import com.futo.platformplayer.toHumanNumber
|
||||||
|
import com.futo.platformplayer.views.LoaderView
|
||||||
import com.futo.platformplayer.views.others.CreatorThumbnail
|
import com.futo.platformplayer.views.others.CreatorThumbnail
|
||||||
import com.futo.platformplayer.views.pills.PillButton
|
import com.futo.platformplayer.views.pills.PillButton
|
||||||
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
||||||
@ -46,6 +48,9 @@ class CommentViewHolder : ViewHolder {
|
|||||||
private val _layoutComment: ConstraintLayout;
|
private val _layoutComment: ConstraintLayout;
|
||||||
private val _buttonDelete: FrameLayout;
|
private val _buttonDelete: FrameLayout;
|
||||||
|
|
||||||
|
private val _containerComments: ConstraintLayout;
|
||||||
|
private val _loader: LoaderView;
|
||||||
|
|
||||||
var onRepliesClick = Event1<IPlatformComment>();
|
var onRepliesClick = Event1<IPlatformComment>();
|
||||||
var onDelete = Event1<IPlatformComment>();
|
var onDelete = Event1<IPlatformComment>();
|
||||||
var onAuthorClick = Event1<IPlatformComment>();
|
var onAuthorClick = Event1<IPlatformComment>();
|
||||||
@ -67,6 +72,9 @@ class CommentViewHolder : ViewHolder {
|
|||||||
_pillRatingLikesDislikes = itemView.findViewById(R.id.rating);
|
_pillRatingLikesDislikes = itemView.findViewById(R.id.rating);
|
||||||
_buttonDelete = itemView.findViewById(R.id.button_delete);
|
_buttonDelete = itemView.findViewById(R.id.button_delete);
|
||||||
|
|
||||||
|
_containerComments = itemView.findViewById(R.id.comment_container);
|
||||||
|
_loader = itemView.findViewById(R.id.loader);
|
||||||
|
|
||||||
_pillRatingLikesDislikes.onLikeDislikeUpdated.subscribe { args ->
|
_pillRatingLikesDislikes.onLikeDislikeUpdated.subscribe { args ->
|
||||||
val c = comment
|
val c = comment
|
||||||
if (c !is PolycentricPlatformComment) {
|
if (c !is PolycentricPlatformComment) {
|
||||||
@ -123,6 +131,33 @@ class CommentViewHolder : ViewHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun bind(comment: IPlatformComment, readonly: Boolean) {
|
fun bind(comment: IPlatformComment, readonly: Boolean) {
|
||||||
|
|
||||||
|
if(comment is LazyComment){
|
||||||
|
if(comment.isAvailable)
|
||||||
|
{
|
||||||
|
comment.getUnderlyingComment()?.let {
|
||||||
|
bind(it, readonly);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_loader.visibility = View.VISIBLE;
|
||||||
|
_loader.start();
|
||||||
|
_containerComments.visibility = View.GONE;
|
||||||
|
comment.setUIHandler {
|
||||||
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||||
|
if (it.isAvailable && it == this@CommentViewHolder.comment)
|
||||||
|
bind(it, readonly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_loader.stop();
|
||||||
|
_loader.visibility = View.GONE;
|
||||||
|
_containerComments.visibility = View.VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
_creatorThumbnail.setThumbnail(comment.author.thumbnail, false);
|
_creatorThumbnail.setThumbnail(comment.author.thumbnail, false);
|
||||||
val polycentricComment = if (comment is PolycentricPlatformComment) comment else null
|
val polycentricComment = if (comment is PolycentricPlatformComment) comment else null
|
||||||
_creatorThumbnail.setHarborAvailable(polycentricComment != null,false, polycentricComment?.eventPointer?.system?.toProto());
|
_creatorThumbnail.setHarborAvailable(polycentricComment != null,false, polycentricComment?.eventPointer?.system?.toProto());
|
||||||
|
@ -90,7 +90,7 @@ class PillRatingLikesDislikes : LinearLayout {
|
|||||||
setRating(rating, hasLiked, hasDisliked);
|
setRating(rating, hasLiked, hasDisliked);
|
||||||
}
|
}
|
||||||
is RatingLikes -> {
|
is RatingLikes -> {
|
||||||
setRating(rating, hasLiked, hasDisliked);
|
setRating(rating, hasLiked);
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
throw Exception("Unknown rating type");
|
throw Exception("Unknown rating type");
|
||||||
@ -98,6 +98,36 @@ class PillRatingLikesDislikes : LinearLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setRating(rating: RatingLikeDislikes, hasLiked: Boolean = false, hasDisliked: Boolean = false) {
|
||||||
|
setLoading(false)
|
||||||
|
|
||||||
|
_textLikes.text = rating.likes.toHumanNumber();
|
||||||
|
_textDislikes.text = rating.dislikes.toHumanNumber();
|
||||||
|
_textLikes.visibility = View.VISIBLE;
|
||||||
|
_textDislikes.visibility = View.VISIBLE;
|
||||||
|
_seperator.visibility = View.VISIBLE;
|
||||||
|
_iconDislikes.visibility = View.VISIBLE;
|
||||||
|
_likes = rating.likes;
|
||||||
|
_dislikes = rating.dislikes;
|
||||||
|
_hasLiked = hasLiked;
|
||||||
|
_hasDisliked = hasDisliked;
|
||||||
|
updateColors();
|
||||||
|
}
|
||||||
|
fun setRating(rating: RatingLikes, hasLiked: Boolean = false) {
|
||||||
|
setLoading(false)
|
||||||
|
|
||||||
|
_textLikes.text = rating.likes.toHumanNumber();
|
||||||
|
_textLikes.visibility = View.VISIBLE;
|
||||||
|
_textDislikes.visibility = View.GONE;
|
||||||
|
_seperator.visibility = View.GONE;
|
||||||
|
_iconDislikes.visibility = View.GONE;
|
||||||
|
_likes = rating.likes;
|
||||||
|
_dislikes = 0;
|
||||||
|
_hasLiked = hasLiked;
|
||||||
|
_hasDisliked = false;
|
||||||
|
updateColors();
|
||||||
|
}
|
||||||
|
|
||||||
fun like(processHandle: ProcessHandle) {
|
fun like(processHandle: ProcessHandle) {
|
||||||
if (_hasDisliked) {
|
if (_hasDisliked) {
|
||||||
_dislikes--;
|
_dislikes--;
|
||||||
@ -155,34 +185,4 @@ class PillRatingLikesDislikes : LinearLayout {
|
|||||||
_iconDislikes.setColorFilter(ContextCompat.getColor(context, R.color.white));
|
_iconDislikes.setColorFilter(ContextCompat.getColor(context, R.color.white));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setRating(rating: RatingLikeDislikes, hasLiked: Boolean = false, hasDisliked: Boolean = false) {
|
|
||||||
setLoading(false)
|
|
||||||
|
|
||||||
_textLikes.text = rating.likes.toHumanNumber();
|
|
||||||
_textDislikes.text = rating.dislikes.toHumanNumber();
|
|
||||||
_textLikes.visibility = View.VISIBLE;
|
|
||||||
_textDislikes.visibility = View.VISIBLE;
|
|
||||||
_seperator.visibility = View.VISIBLE;
|
|
||||||
_iconDislikes.visibility = View.VISIBLE;
|
|
||||||
_likes = rating.likes;
|
|
||||||
_dislikes = rating.dislikes;
|
|
||||||
_hasLiked = hasLiked;
|
|
||||||
_hasDisliked = hasDisliked;
|
|
||||||
updateColors();
|
|
||||||
}
|
|
||||||
fun setRating(rating: RatingLikes, hasLiked: Boolean = false) {
|
|
||||||
setLoading(false)
|
|
||||||
|
|
||||||
_textLikes.text = rating.likes.toHumanNumber();
|
|
||||||
_textLikes.visibility = View.VISIBLE;
|
|
||||||
_textDislikes.visibility = View.GONE;
|
|
||||||
_seperator.visibility = View.GONE;
|
|
||||||
_iconDislikes.visibility = View.GONE;
|
|
||||||
_likes = rating.likes;
|
|
||||||
_dislikes = 0;
|
|
||||||
_hasLiked = hasLiked;
|
|
||||||
_hasDisliked = false;
|
|
||||||
updateColors();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -11,161 +11,179 @@
|
|||||||
android:layout_marginEnd="14dp"
|
android:layout_marginEnd="14dp"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.futo.platformplayer.views.others.CreatorThumbnail
|
<com.futo.platformplayer.views.LoaderView
|
||||||
android:id="@+id/image_thumbnail"
|
android:id="@+id/loader"
|
||||||
android:layout_width="25dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="25dp"
|
android:layout_height="40dp"
|
||||||
android:contentDescription="@string/channel_image"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@drawable/placeholder_channel_thumbnail" />
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_author"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:fontFamily="@font/inter_regular"
|
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/image_thumbnail"
|
|
||||||
tools:text="ShortCircuit" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_metadata"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:fontFamily="@font/inter_regular"
|
|
||||||
android:textColor="@color/gray_ac"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/text_author"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/text_author"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="@id/text_author"
|
android:layout_marginTop="50dp"
|
||||||
tools:text=" • 3 years ago" />
|
android:layout_marginBottom="50dp" />
|
||||||
|
|
||||||
<com.futo.platformplayer.views.behavior.NonScrollingTextView
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/text_body"
|
android:id="@+id/comment_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_marginTop="5dp"
|
|
||||||
android:layout_marginStart="10dp"
|
|
||||||
android:background="@color/transparent"
|
|
||||||
android:fontFamily="@font/inter_regular"
|
|
||||||
android:isScrollContainer="false"
|
|
||||||
android:textColor="#CCCCCC"
|
|
||||||
android:textSize="13sp"
|
|
||||||
android:maxLines="100"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_metadata"
|
|
||||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
tools:text="@string/lorem_ipsum" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintLeft_toLeftOf="@id/text_body"
|
android:visibility="gone"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_body"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginLeft="-10dp"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_marginTop="8dp"
|
app:layout_constraintRight_toRightOf="parent">
|
||||||
android:gravity="center_vertical">
|
<com.futo.platformplayer.views.others.CreatorThumbnail
|
||||||
|
android:id="@+id/image_thumbnail"
|
||||||
<com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
android:layout_width="25dp"
|
||||||
android:id="@+id/rating"
|
android:layout_height="25dp"
|
||||||
android:layout_width="wrap_content"
|
android:contentDescription="@string/channel_image"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
android:layout_marginStart="9dp" />
|
tools:src="@drawable/placeholder_channel_thumbnail" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_author"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:fontFamily="@font/inter_regular"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/image_thumbnail"
|
||||||
|
tools:text="ShortCircuit" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_metadata"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:fontFamily="@font/inter_regular"
|
||||||
|
android:textColor="@color/gray_ac"
|
||||||
|
android:textSize="14sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/text_author"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/text_author"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/text_author"
|
||||||
|
tools:text=" • 3 years ago" />
|
||||||
|
|
||||||
|
<com.futo.platformplayer.views.behavior.NonScrollingTextView
|
||||||
|
android:id="@+id/text_body"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:background="@color/transparent"
|
||||||
|
android:fontFamily="@font/inter_regular"
|
||||||
|
android:isScrollContainer="false"
|
||||||
|
android:textColor="#CCCCCC"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:maxLines="100"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/text_metadata"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||||
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
tools:text="@string/lorem_ipsum" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_rating"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_marginStart="10dp"
|
android:layout_width="0dp"
|
||||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintLeft_toLeftOf="@id/text_body"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_body"
|
app:layout_constraintTop_toBottomOf="@id/text_body"
|
||||||
|
android:layout_marginLeft="-10dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:gravity="center_vertical">
|
android:gravity="center_vertical">
|
||||||
|
|
||||||
<ImageView
|
<com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
||||||
android:id="@+id/image_like_icon"
|
android:id="@+id/rating"
|
||||||
android:layout_width="18dp"
|
|
||||||
android:layout_height="18dp"
|
|
||||||
android:contentDescription="@string/cd_image_like_icon"
|
|
||||||
app:srcCompat="@drawable/ic_thumb_up" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_likes"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="18dp"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
android:layout_marginStart="8dp"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="500K"
|
android:layout_marginStart="9dp" />
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="13dp" />
|
|
||||||
|
|
||||||
<ImageView
|
<LinearLayout
|
||||||
android:id="@+id/image_dislike_icon"
|
android:id="@+id/layout_rating"
|
||||||
android:layout_width="18dp"
|
|
||||||
android:layout_height="18dp"
|
|
||||||
android:contentDescription="@string/cd_image_dislike_icon"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginTop="2dp"
|
|
||||||
app:srcCompat="@drawable/ic_thumb_down" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/text_dislikes"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="18dp"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:orientation="horizontal"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="10dp"
|
||||||
tools:text="500K"
|
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||||
android:textColor="@color/white"
|
app:layout_constraintTop_toBottomOf="@id/text_body"
|
||||||
android:textSize="13dp" />
|
android:gravity="center_vertical">
|
||||||
</LinearLayout>
|
|
||||||
<com.futo.platformplayer.views.pills.PillButton
|
|
||||||
android:id="@+id/button_replies"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:contentDescription="@string/cd_button_replies"
|
|
||||||
app:pillIcon="@drawable/ic_forum"
|
|
||||||
app:pillText="55 Replies"
|
|
||||||
android:layout_marginStart="15dp" />
|
|
||||||
|
|
||||||
<Space android:layout_width="0dp"
|
<ImageView
|
||||||
android:layout_height="match_parent"
|
android:id="@+id/image_like_icon"
|
||||||
android:layout_weight="1" />
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:contentDescription="@string/cd_image_like_icon"
|
||||||
|
app:srcCompat="@drawable/ic_thumb_up" />
|
||||||
|
|
||||||
<FrameLayout
|
<TextView
|
||||||
android:id="@+id/button_delete"
|
android:id="@+id/text_likes"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="18dp"
|
||||||
android:background="@drawable/background_pill_pred"
|
android:gravity="center_vertical"
|
||||||
android:paddingTop="8dp"
|
android:layout_marginStart="8dp"
|
||||||
android:paddingBottom="8dp"
|
tools:text="500K"
|
||||||
android:paddingStart="16dp"
|
android:textColor="@color/white"
|
||||||
android:paddingEnd="16dp"
|
android:textSize="13dp" />
|
||||||
android:layout_marginStart="12dp">
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/pill_text"
|
android:id="@+id/image_dislike_icon"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:contentDescription="@string/cd_image_dislike_icon"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
app:srcCompat="@drawable/ic_thumb_down" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_dislikes"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
tools:text="500K"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="13dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
<com.futo.platformplayer.views.pills.PillButton
|
||||||
|
android:id="@+id/button_replies"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/cd_button_replies"
|
||||||
|
app:pillIcon="@drawable/ic_forum"
|
||||||
|
app:pillText="55 Replies"
|
||||||
|
android:layout_marginStart="15dp" />
|
||||||
|
|
||||||
|
<Space android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:textColor="@color/white"
|
android:layout_weight="1" />
|
||||||
android:textSize="13dp"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:fontFamily="@font/inter_light"
|
|
||||||
android:text="@string/delete" />
|
|
||||||
</FrameLayout>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/button_delete"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/background_pill_pred"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:layout_marginStart="12dp">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pill_text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="13dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:fontFamily="@font/inter_light"
|
||||||
|
android:text="@string/delete" />
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
x
Reference in New Issue
Block a user