mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Proper implementation for replies/likes/dislikes in the comment tab.
This commit is contained in:
parent
c806ff2e33
commit
3387c727d1
5 changed files with 113 additions and 69 deletions
|
@ -33,6 +33,7 @@ import com.futo.polycentric.core.PublicKey
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.UnknownHostException
|
||||
import java.util.IdentityHashMap
|
||||
|
||||
class CommentsFragment : MainFragment() {
|
||||
override val isMainView : Boolean = true
|
||||
|
@ -84,6 +85,7 @@ class CommentsFragment : MainFragment() {
|
|||
private var _loading = false;
|
||||
private val _repliesOverlay: RepliesOverlay;
|
||||
private var _repliesAnimator: ViewPropertyAnimator? = null;
|
||||
private val _cache: IdentityHashMap<IPlatformComment, StatePolycentric.LikesDislikesReplies> = IdentityHashMap()
|
||||
|
||||
private val _taskLoadComments = if(!isInEditMode) TaskHandler<PublicKey, List<IPlatformComment>>(
|
||||
StateApp.instance.scopeGetter, { StatePolycentric.instance.getSystemComments(context, it) })
|
||||
|
@ -111,7 +113,7 @@ class CommentsFragment : MainFragment() {
|
|||
childCountGetter = { _comments.size },
|
||||
childViewHolderBinder = { viewHolder, position -> viewHolder.bind(_comments[position]); },
|
||||
childViewHolderFactory = { viewGroup, _ ->
|
||||
val holder = CommentWithReferenceViewHolder(viewGroup);
|
||||
val holder = CommentWithReferenceViewHolder(viewGroup, _cache);
|
||||
holder.onDelete.subscribe(::onDelete);
|
||||
holder.onRepliesClick.subscribe(::onRepliesClick);
|
||||
return@InsertedViewAdapterWithLoader holder;
|
||||
|
@ -202,15 +204,21 @@ class CommentsFragment : MainFragment() {
|
|||
}
|
||||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
var parentComment: PolycentricPlatformComment = c;
|
||||
_repliesOverlay.load(false, metadata, c.contextUrl, c.reference, c,
|
||||
{ StatePolycentric.instance.getCommentPager(c.contextUrl, c.reference) },
|
||||
{
|
||||
val newComment = parentComment.cloneWithUpdatedReplyCount((parentComment.replyCount ?: 0) + 1);
|
||||
val index = _comments.indexOf(c);
|
||||
_comments[index] = newComment;
|
||||
_adapterComments.notifyItemChanged(_adapterComments.childToParentPosition(index));
|
||||
parentComment = newComment;
|
||||
{ newComment ->
|
||||
synchronized(_cache) {
|
||||
_cache.remove(c)
|
||||
}
|
||||
|
||||
val newCommentIndex = if (_spinnerSortBy.selectedItemPosition == 0) {
|
||||
_comments.indexOfFirst { it.date!! < newComment.date!! }.takeIf { it != -1 } ?: _comments.size
|
||||
} else {
|
||||
_comments.indexOfFirst { it.date!! > newComment.date!! }.takeIf { it != -1 } ?: _comments.size
|
||||
}
|
||||
|
||||
_comments.add(newCommentIndex, newComment)
|
||||
_adapterComments.notifyItemInserted(_adapterComments.childToParentPosition(newCommentIndex))
|
||||
});
|
||||
} else {
|
||||
_repliesOverlay.load(true, metadata, null, null, c, { StatePlatform.instance.getSubComments(c) });
|
||||
|
|
|
@ -11,17 +11,12 @@ 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.PolycentricPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||
import com.futo.platformplayer.api.media.models.contents.PlatformContentPlaceholder
|
||||
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
|
||||
import com.futo.platformplayer.api.media.structures.DedupContentPager
|
||||
import com.futo.platformplayer.api.media.structures.EmptyPager
|
||||
import com.futo.platformplayer.api.media.structures.IAsyncPager
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.api.media.structures.MultiChronoContentPager
|
||||
import com.futo.platformplayer.api.media.structures.PlaceholderPager
|
||||
import com.futo.platformplayer.api.media.structures.RefreshChronoContentPager
|
||||
import com.futo.platformplayer.api.media.structures.RefreshDedupContentPager
|
||||
import com.futo.platformplayer.api.media.structures.RefreshDistributionContentPager
|
||||
import com.futo.platformplayer.awaitFirstDeferred
|
||||
import com.futo.platformplayer.dp
|
||||
import com.futo.platformplayer.fragment.mainactivity.main.PolycentricProfile
|
||||
|
@ -247,28 +242,36 @@ class StatePolycentric {
|
|||
return posts
|
||||
}
|
||||
|
||||
suspend fun getLiveComment(contextUrl: String, reference: Protocol.Reference): PolycentricPlatformComment {
|
||||
val response = ApiMethods.getQueryReferences(PolycentricCache.SERVER, reference, null,
|
||||
Protocol.QueryReferencesRequestEvents.newBuilder()
|
||||
.setFromType(ContentType.POST.value)
|
||||
.addAllCountLwwElementReferences(arrayListOf(
|
||||
Protocol.QueryReferencesRequestCountLWWElementReferences.newBuilder()
|
||||
.setFromType(ContentType.OPINION.value)
|
||||
.setValue(ByteString.copyFrom(Opinion.like.data))
|
||||
.build(),
|
||||
Protocol.QueryReferencesRequestCountLWWElementReferences.newBuilder()
|
||||
.setFromType(ContentType.OPINION.value)
|
||||
.setValue(ByteString.copyFrom(Opinion.dislike.data))
|
||||
.build()
|
||||
))
|
||||
.addCountReferences(
|
||||
Protocol.QueryReferencesRequestCountReferences.newBuilder()
|
||||
.setFromType(ContentType.POST.value)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
data class LikesDislikesReplies(
|
||||
var likes: Long,
|
||||
var dislikes: Long,
|
||||
var replyCount: Long
|
||||
)
|
||||
|
||||
return mapQueryReferences(contextUrl, response).first()
|
||||
suspend fun getLikesDislikesReplies(reference: Protocol.Reference): LikesDislikesReplies {
|
||||
val response = ApiMethods.getQueryReferences(PolycentricCache.SERVER, reference, null,
|
||||
null,
|
||||
listOf(
|
||||
Protocol.QueryReferencesRequestCountLWWElementReferences.newBuilder()
|
||||
.setFromType(ContentType.OPINION.value)
|
||||
.setValue(ByteString.copyFrom(Opinion.like.data))
|
||||
.build(),
|
||||
Protocol.QueryReferencesRequestCountLWWElementReferences.newBuilder()
|
||||
.setFromType(ContentType.OPINION.value)
|
||||
.setValue(ByteString.copyFrom(Opinion.dislike.data))
|
||||
.build()
|
||||
),
|
||||
listOf(
|
||||
Protocol.QueryReferencesRequestCountReferences.newBuilder()
|
||||
.setFromType(ContentType.POST.value)
|
||||
.build()
|
||||
)
|
||||
);
|
||||
|
||||
val likes = response.countsList[0];
|
||||
val dislikes = response.countsList[1];
|
||||
val replyCount = response.countsList[2];
|
||||
return LikesDislikesReplies(likes, dislikes, replyCount)
|
||||
}
|
||||
|
||||
suspend fun getCommentPager(contextUrl: String, reference: Protocol.Reference): IPager<IPlatformComment> {
|
||||
|
@ -347,7 +350,6 @@ class StatePolycentric {
|
|||
|
||||
try {
|
||||
val post = Protocol.Post.parseFrom(ev.content);
|
||||
val id = ev.system.toProto().key.toByteArray().toBase64();
|
||||
val likes = it.countsList[0];
|
||||
val dislikes = it.countsList[1];
|
||||
val replies = it.countsList[2];
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.futo.platformplayer.views.adapters
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -22,6 +23,8 @@ import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
|||
import com.futo.polycentric.core.Opinion
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import userpackage.Protocol
|
||||
import java.util.IdentityHashMap
|
||||
|
||||
class CommentWithReferenceViewHolder : ViewHolder {
|
||||
private val _creatorThumbnail: CreatorThumbnail;
|
||||
|
@ -32,14 +35,18 @@ class CommentWithReferenceViewHolder : ViewHolder {
|
|||
private val _pillRatingLikesDislikes: PillRatingLikesDislikes;
|
||||
private val _layoutComment: ConstraintLayout;
|
||||
private val _buttonDelete: FrameLayout;
|
||||
private val _cache: IdentityHashMap<IPlatformComment, StatePolycentric.LikesDislikesReplies>;
|
||||
private var _likesDislikesReplies: StatePolycentric.LikesDislikesReplies? = null;
|
||||
|
||||
private val _taskGetLiveComment = TaskHandler<PolycentricPlatformComment, PolycentricPlatformComment>(StateApp.instance.scopeGetter, { StatePolycentric.instance.getLiveComment(it.contextUrl, it.reference) })
|
||||
private val _taskGetLiveComment = TaskHandler(StateApp.instance.scopeGetter, ::getLikesDislikesReplies)
|
||||
.success {
|
||||
bind(it, true);
|
||||
_likesDislikesReplies = it
|
||||
updateLikesDislikesReplies()
|
||||
}
|
||||
.exception<Throwable> {
|
||||
Logger.w(TAG, "Failed to get live comment.", it);
|
||||
//TODO: Show error
|
||||
hideLikesDislikesReplies()
|
||||
}
|
||||
|
||||
var onRepliesClick = Event1<IPlatformComment>();
|
||||
|
@ -47,7 +54,7 @@ class CommentWithReferenceViewHolder : ViewHolder {
|
|||
var comment: IPlatformComment? = null
|
||||
private set;
|
||||
|
||||
constructor(viewGroup: ViewGroup) : super(LayoutInflater.from(viewGroup.context).inflate(R.layout.list_comment_with_reference, viewGroup, false)) {
|
||||
constructor(viewGroup: ViewGroup, cache: IdentityHashMap<IPlatformComment, StatePolycentric.LikesDislikesReplies>) : super(LayoutInflater.from(viewGroup.context).inflate(R.layout.list_comment_with_reference, viewGroup, false)) {
|
||||
_layoutComment = itemView.findViewById(R.id.layout_comment);
|
||||
_creatorThumbnail = itemView.findViewById(R.id.image_thumbnail);
|
||||
_textAuthor = itemView.findViewById(R.id.text_author);
|
||||
|
@ -56,6 +63,7 @@ class CommentWithReferenceViewHolder : ViewHolder {
|
|||
_buttonReplies = itemView.findViewById(R.id.button_replies);
|
||||
_pillRatingLikesDislikes = itemView.findViewById(R.id.rating);
|
||||
_buttonDelete = itemView.findViewById(R.id.button_delete)
|
||||
_cache = cache
|
||||
|
||||
_pillRatingLikesDislikes.onLikeDislikeUpdated.subscribe { args ->
|
||||
val c = comment
|
||||
|
@ -99,7 +107,18 @@ class CommentWithReferenceViewHolder : ViewHolder {
|
|||
_textBody.setPlatformPlayerLinkMovementMethod(viewGroup.context);
|
||||
}
|
||||
|
||||
fun bind(comment: IPlatformComment, live: Boolean = false) {
|
||||
private suspend fun getLikesDislikesReplies(c: PolycentricPlatformComment): StatePolycentric.LikesDislikesReplies {
|
||||
val likesDislikesReplies = StatePolycentric.instance.getLikesDislikesReplies(c.reference)
|
||||
synchronized(_cache) {
|
||||
_cache[c] = likesDislikesReplies
|
||||
}
|
||||
return likesDislikesReplies
|
||||
}
|
||||
|
||||
fun bind(comment: IPlatformComment) {
|
||||
Log.i(TAG, "bind")
|
||||
|
||||
_likesDislikesReplies = null;
|
||||
_taskGetLiveComment.cancel()
|
||||
|
||||
_creatorThumbnail.setThumbnail(comment.author.thumbnail, false);
|
||||
|
@ -123,40 +142,51 @@ class CommentWithReferenceViewHolder : ViewHolder {
|
|||
|
||||
_textBody.text = comment.message.fixHtmlLinks();
|
||||
|
||||
if (comment is PolycentricPlatformComment) {
|
||||
if (live) {
|
||||
val hasLiked = StatePolycentric.instance.hasLiked(comment.reference);
|
||||
val hasDisliked = StatePolycentric.instance.hasDisliked(comment.reference);
|
||||
_pillRatingLikesDislikes.setRating(comment.rating, hasLiked, hasDisliked);
|
||||
} else {
|
||||
_pillRatingLikesDislikes.setLoading(true)
|
||||
this.comment = comment;
|
||||
updateLikesDislikesReplies();
|
||||
}
|
||||
|
||||
private fun updateLikesDislikesReplies() {
|
||||
Log.i(TAG, "updateLikesDislikesReplies")
|
||||
|
||||
val c = comment ?: return
|
||||
if (c is PolycentricPlatformComment) {
|
||||
if (_likesDislikesReplies == null) {
|
||||
Log.i(TAG, "updateLikesDislikesReplies retrieving from cache")
|
||||
|
||||
synchronized(_cache) {
|
||||
_likesDislikesReplies = _cache[c]
|
||||
}
|
||||
}
|
||||
|
||||
if (live) {
|
||||
val likesDislikesReplies = _likesDislikesReplies
|
||||
if (likesDislikesReplies != null) {
|
||||
Log.i(TAG, "updateLikesDislikesReplies set")
|
||||
|
||||
val hasLiked = StatePolycentric.instance.hasLiked(c.reference);
|
||||
val hasDisliked = StatePolycentric.instance.hasDisliked(c.reference);
|
||||
_pillRatingLikesDislikes.setRating(RatingLikeDislikes(likesDislikesReplies.likes, likesDislikesReplies.dislikes), hasLiked, hasDisliked);
|
||||
|
||||
_buttonReplies.setLoading(false)
|
||||
|
||||
val replies = comment.replyCount ?: 0;
|
||||
if (replies > 0) {
|
||||
_buttonReplies.visibility = View.VISIBLE;
|
||||
_buttonReplies.text.text = "$replies " + itemView.context.getString(R.string.replies);
|
||||
} else {
|
||||
_buttonReplies.visibility = View.GONE;
|
||||
}
|
||||
val replies = likesDislikesReplies.replyCount ?: 0;
|
||||
_buttonReplies.visibility = View.VISIBLE;
|
||||
_buttonReplies.text.text = "$replies " + itemView.context.getString(R.string.replies);
|
||||
} else {
|
||||
_buttonReplies.setLoading(true)
|
||||
}
|
||||
Log.i(TAG, "updateLikesDislikesReplies to load")
|
||||
|
||||
if (false) {
|
||||
//Restore from cached
|
||||
} else {
|
||||
//_taskGetLiveComment.run(comment)
|
||||
_pillRatingLikesDislikes.setLoading(true)
|
||||
_buttonReplies.setLoading(true)
|
||||
_taskGetLiveComment.run(c)
|
||||
}
|
||||
} else {
|
||||
_pillRatingLikesDislikes.visibility = View.GONE
|
||||
_buttonReplies.visibility = View.GONE
|
||||
hideLikesDislikesReplies()
|
||||
}
|
||||
}
|
||||
|
||||
this.comment = comment;
|
||||
private fun hideLikesDislikesReplies() {
|
||||
_pillRatingLikesDislikes.visibility = View.GONE
|
||||
_buttonReplies.visibility = View.GONE
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -159,6 +159,8 @@ 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;
|
||||
|
@ -172,6 +174,8 @@ class PillRatingLikesDislikes : LinearLayout {
|
|||
updateColors();
|
||||
}
|
||||
fun setRating(rating: RatingLikes, hasLiked: Boolean = false) {
|
||||
setLoading(false)
|
||||
|
||||
_textLikes.text = rating.likes.toHumanNumber();
|
||||
_textLikes.visibility = View.VISIBLE;
|
||||
_textDislikes.visibility = View.GONE;
|
||||
|
|
|
@ -61,6 +61,12 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.futo.platformplayer.views.overlays.RepliesOverlay
|
||||
android:id="@+id/replies_overlay"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout android:id="@+id/layout_not_logged_in"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
@ -81,12 +87,6 @@
|
|||
android:paddingEnd="28dp"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
|
||||
<com.futo.platformplayer.views.overlays.RepliesOverlay
|
||||
android:id="@+id/replies_overlay"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_login"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
Loading…
Add table
Reference in a new issue