Support for per-comment lazy loading for Polycentric

This commit is contained in:
Kelvin 2024-11-28 16:24:01 +01:00
parent da27517fcf
commit b45d4c0557
5 changed files with 332 additions and 206 deletions

View file

@ -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);
}
}

View file

@ -10,6 +10,7 @@ import com.futo.platformplayer.activities.PolycentricHomeActivity
import com.futo.platformplayer.api.media.PlatformID
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.LazyComment
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.ratings.RatingLikeDislikes
@ -46,6 +47,7 @@ import com.google.protobuf.ByteString
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import userpackage.Protocol
@ -53,6 +55,7 @@ import userpackage.Protocol.Reference
import java.time.Instant
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.util.concurrent.ForkJoinPool
class StatePolycentric {
private data class LikeDislikeEntry(val unixMilliseconds: Long, val hasLiked: Boolean, val hasDisliked: Boolean);
@ -63,6 +66,9 @@ class StatePolycentric {
private var _transientEnabled = true
val enabled get() = _transientEnabled && Settings.instance.other.polycentricEnabled
private val _commentPool = ForkJoinPool(2);
private val _commentPoolDispatcher = _commentPool.asCoroutineDispatcher();
fun load(context: Context) {
if (!enabled) {
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 {
val sev = SignedEvent.fromProto(it.event);
val ev = sev.event;
@ -524,49 +530,53 @@ class StatePolycentric {
val dislikes = it.countsList[1];
val replies = it.countsList[2];
val profileEvents = ApiMethods.getQueryLatest(
PolycentricCache.SERVER,
ev.system.toProto(),
listOf(
ContentType.AVATAR.value,
ContentType.USERNAME.value
)
).eventsList.map { e -> SignedEvent.fromProto(e) }.groupBy { e -> e.event.contentType }
.map { (_, events) -> events.maxBy { x -> x.event.unixMilliseconds ?: 0 } };
val scope = StateApp.instance.scopeOrNull ?: return@mapNotNull null;
return@mapNotNull LazyComment(scope.async(_commentPoolDispatcher){
Logger.i(TAG, "Fetching comment data for [" + ev.system.key.toBase64() + "]");
val profileEvents = ApiMethods.getQueryLatest(
PolycentricCache.SERVER,
ev.system.toProto(),
listOf(
ContentType.AVATAR.value,
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 avatarEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.AVATAR.value };
val imageBundle = if (avatarEvent != null) {
val lwwElementValue = avatarEvent.event.lwwElement?.value;
if (lwwElementValue != null) {
Protocol.ImageBundle.parseFrom(lwwElementValue)
val nameEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.USERNAME.value };
val avatarEvent = profileEvents.firstOrNull { e -> e.event.contentType == ContentType.AVATAR.value };
val imageBundle = if (avatarEvent != null) {
val lwwElementValue = avatarEvent.event.lwwElement?.value;
if (lwwElementValue != null) {
Protocol.ImageBundle.parseFrom(lwwElementValue)
} else {
null
}
} else {
null
}
} else {
null
}
val unixMilliseconds = ev.unixMilliseconds
//TODO: Don't use single hardcoded sderver here
val systemLinkUrl = ev.system.systemToURLInfoSystemLinkUrl(listOf(PolycentricCache.SERVER));
val dp_25 = 25.dp(StateApp.instance.context.resources)
return@mapNotNull PolycentricPlatformComment(
contextUrl = contextUrl,
author = PlatformAuthorLink(
id = PlatformID("polycentric", systemLinkUrl, null, ClaimType.POLYCENTRIC.value.toInt()),
name = nameEvent?.event?.lwwElement?.value?.decodeToString() ?: "Unknown",
url = systemLinkUrl,
thumbnail = imageBundle?.selectBestImage(dp_25 * dp_25)?.let { img -> img.toURLInfoSystemLinkUrl(ev.system.toProto(), img.process, listOf(PolycentricCache.SERVER)) },
subscribers = null
),
msg = if (post.content.count() > PolycentricPlatformComment.MAX_COMMENT_SIZE) post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE) else post.content,
rating = RatingLikeDislikes(likes, dislikes),
date = if (unixMilliseconds != null) Instant.ofEpochMilli(unixMilliseconds).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
replyCount = replies.toInt(),
eventPointer = sev.toPointer(),
parentReference = sev.event.references.getOrNull(0)
);
val unixMilliseconds = ev.unixMilliseconds
//TODO: Don't use single hardcoded sderver here
val systemLinkUrl = ev.system.systemToURLInfoSystemLinkUrl(listOf(PolycentricCache.SERVER));
val dp_25 = 25.dp(StateApp.instance.context.resources)
return@async PolycentricPlatformComment(
contextUrl = contextUrl,
author = PlatformAuthorLink(
id = PlatformID("polycentric", systemLinkUrl, null, ClaimType.POLYCENTRIC.value.toInt()),
name = nameEvent?.event?.lwwElement?.value?.decodeToString() ?: "Unknown",
url = systemLinkUrl,
thumbnail = imageBundle?.selectBestImage(dp_25 * dp_25)?.let { img -> img.toURLInfoSystemLinkUrl(ev.system.toProto(), img.process, listOf(PolycentricCache.SERVER)) },
subscribers = null
),
msg = if (post.content.count() > PolycentricPlatformComment.MAX_COMMENT_SIZE) post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE) else post.content,
rating = RatingLikeDislikes(likes, dislikes),
date = if (unixMilliseconds != null) Instant.ofEpochMilli(unixMilliseconds).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
replyCount = replies.toInt(),
eventPointer = sev.toPointer(),
parentReference = sev.event.references.getOrNull(0)
);
});
} catch (e: Throwable) {
return@mapNotNull null;
}

View file

@ -12,6 +12,7 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.futo.platformplayer.R
import com.futo.platformplayer.Settings
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.ratings.RatingLikeDislikes
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.toHumanNowDiffString
import com.futo.platformplayer.toHumanNumber
import com.futo.platformplayer.views.LoaderView
import com.futo.platformplayer.views.others.CreatorThumbnail
import com.futo.platformplayer.views.pills.PillButton
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
@ -46,6 +48,9 @@ class CommentViewHolder : ViewHolder {
private val _layoutComment: ConstraintLayout;
private val _buttonDelete: FrameLayout;
private val _containerComments: ConstraintLayout;
private val _loader: LoaderView;
var onRepliesClick = Event1<IPlatformComment>();
var onDelete = Event1<IPlatformComment>();
var onAuthorClick = Event1<IPlatformComment>();
@ -67,6 +72,9 @@ class CommentViewHolder : ViewHolder {
_pillRatingLikesDislikes = itemView.findViewById(R.id.rating);
_buttonDelete = itemView.findViewById(R.id.button_delete);
_containerComments = itemView.findViewById(R.id.comment_container);
_loader = itemView.findViewById(R.id.loader);
_pillRatingLikesDislikes.onLikeDislikeUpdated.subscribe { args ->
val c = comment
if (c !is PolycentricPlatformComment) {
@ -123,6 +131,33 @@ class CommentViewHolder : ViewHolder {
}
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);
val polycentricComment = if (comment is PolycentricPlatformComment) comment else null
_creatorThumbnail.setHarborAvailable(polycentricComment != null,false, polycentricComment?.eventPointer?.system?.toProto());

View file

@ -90,7 +90,7 @@ class PillRatingLikesDislikes : LinearLayout {
setRating(rating, hasLiked, hasDisliked);
}
is RatingLikes -> {
setRating(rating, hasLiked, hasDisliked);
setRating(rating, hasLiked);
}
else -> {
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) {
if (_hasDisliked) {
_dislikes--;
@ -155,34 +185,4 @@ class PillRatingLikesDislikes : LinearLayout {
_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();
}
}

View file

@ -11,161 +11,179 @@
android:layout_marginEnd="14dp"
android:orientation="vertical">
<com.futo.platformplayer.views.others.CreatorThumbnail
android:id="@+id/image_thumbnail"
android:layout_width="25dp"
android:layout_height="25dp"
android:contentDescription="@string/channel_image"
app:layout_constraintLeft_toLeftOf="parent"
<com.futo.platformplayer.views.LoaderView
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
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_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="@id/text_author"
tools:text=" • 3 years ago" />
android:layout_marginTop="50dp"
android:layout_marginBottom="50dp" />
<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
android:orientation="horizontal"
android:layout_width="0dp"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/comment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@id/text_body"
app:layout_constraintTop_toBottomOf="@id/text_body"
android:layout_marginLeft="-10dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical">
<com.futo.platformplayer.views.pills.PillRatingLikesDislikes
android:id="@+id/rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
<com.futo.platformplayer.views.others.CreatorThumbnail
android:id="@+id/image_thumbnail"
android:layout_width="25dp"
android:layout_height="25dp"
android:contentDescription="@string/channel_image"
app:layout_constraintLeft_toLeftOf="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
android:id="@+id/layout_rating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginStart="10dp"
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="@id/text_body"
app:layout_constraintTop_toBottomOf="@id/text_body"
android:layout_marginLeft="-10dp"
android:layout_marginTop="8dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/image_like_icon"
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"
<com.futo.platformplayer.views.pills.PillRatingLikesDislikes
android:id="@+id/rating"
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" />
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginStart="9dp" />
<ImageView
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"
<LinearLayout
android:id="@+id/layout_rating"
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_height="wrap_content"
android:contentDescription="@string/cd_button_replies"
app:pillIcon="@drawable/ic_forum"
app:pillText="55 Replies"
android:layout_marginStart="15dp" />
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginStart="10dp"
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
app:layout_constraintTop_toBottomOf="@id/text_body"
android:gravity="center_vertical">
<Space android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<ImageView
android:id="@+id/image_like_icon"
android:layout_width="18dp"
android:layout_height="18dp"
android:contentDescription="@string/cd_image_like_icon"
app:srcCompat="@drawable/ic_thumb_up" />
<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"
<TextView
android:id="@+id/text_likes"
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" />
<ImageView
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_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:textColor="@color/white"
android:textSize="13dp"
android:gravity="center_vertical"
android:fontFamily="@font/inter_light"
android:text="@string/delete" />
</FrameLayout>
</LinearLayout>
android:layout_weight="1" />
<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>