mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-19 19:14:51 +00:00
Support for per-comment lazy loading for Polycentric
This commit is contained in:
parent
da27517fcf
commit
b45d4c0557
5 changed files with 332 additions and 206 deletions
|
@ -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.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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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>
|
Loading…
Add table
Reference in a new issue