feat: replies in stories

This commit is contained in:
rebelonion 2024-05-12 21:44:10 -05:00
parent d355cc561e
commit 001c384d11
8 changed files with 220 additions and 32 deletions

View file

@ -11,6 +11,7 @@ import ani.dantotsu.connections.anilist.api.FuzzyDate
import ani.dantotsu.connections.anilist.api.NotificationResponse import ani.dantotsu.connections.anilist.api.NotificationResponse
import ani.dantotsu.connections.anilist.api.Page import ani.dantotsu.connections.anilist.api.Page
import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.connections.anilist.api.Query
import ani.dantotsu.connections.anilist.api.ReplyResponse
import ani.dantotsu.connections.anilist.api.ToggleLike import ani.dantotsu.connections.anilist.api.ToggleLike
import ani.dantotsu.currContext import ani.dantotsu.currContext
import ani.dantotsu.isOnline import ani.dantotsu.isOnline
@ -1612,8 +1613,17 @@ Page(page:$page,perPage:50) {
force = true force = true
) )
} }
suspend fun getReplies(
activityId: Int,
page: Int = 1
) : ReplyResponse? {
val query = """{Page(page:$page,perPage:50){activityReplies(activityId:$activityId){id userId activityId text(asHtml:true)likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}}}"""
return executeQuery(query, force = true)
}
private fun status(page: Int = 1): String { private fun status(page: Int = 1): String {
return """Page(page:$page,perPage:50){activities(isFollowing: true,sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id isAdult title{english romaji native userPreferred}bannerImage coverImage{extraLarge medium large}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id type createdAt}}}""" return """Page(page:$page,perPage:50){activities(isFollowing: true,sort:ID_DESC){__typename ... on TextActivity{id userId type replyCount text(asHtml:true)siteUrl isLocked isSubscribed replyCount likeCount isLiked createdAt user{id name bannerImage avatar{medium large}}likes{id name bannerImage avatar{medium large}}}... on ListActivity{id userId type replyCount status progress siteUrl isLocked isSubscribed replyCount likeCount isLiked isPinned createdAt user{id name bannerImage avatar{medium large}}media{id isAdult title{english romaji native userPreferred}bannerImage coverImage{extraLarge medium large}}likes{id name bannerImage avatar{medium large}}}... on MessageActivity{id type createdAt}}}"""
} }
suspend fun getUpcomingAnime(id: String): List<Media> { suspend fun getUpcomingAnime(id: String): List<Media> {

View file

@ -74,6 +74,24 @@ data class Activity(
val likes: List<User>?, val likes: List<User>?,
) : java.io.Serializable ) : java.io.Serializable
@Serializable
data class ReplyResponse(
@SerialName("data")
val data: Data
) : java.io.Serializable {
@Serializable
data class Data(
@SerialName("Page")
val page: ReplyPage
) : java.io.Serializable
}
@Serializable
data class ReplyPage(
@SerialName("activityReplies")
val activityReplies: List<ActivityReply>
) : java.io.Serializable
@Serializable @Serializable
data class ActivityReply( data class ActivityReply(
@SerialName("id") @SerialName("id")

View file

@ -0,0 +1,94 @@
package ani.dantotsu.home.status
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.BottomSheetDialogFragment
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.ActivityReply
import ani.dantotsu.databinding.BottomSheetRecyclerBinding
import ani.dantotsu.profile.activity.ActivityReplyItem
import ani.dantotsu.snackString
import ani.dantotsu.util.MarkdownCreatorActivity
import com.xwray.groupie.GroupieAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class RepliesBottomDialog : BottomSheetDialogFragment() {
private var _binding: BottomSheetRecyclerBinding? = null
private val binding get() = _binding!!
private val adapter: GroupieAdapter = GroupieAdapter()
private val replies: MutableList<ActivityReply> = mutableListOf()
private var activityId: Int = -1
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = BottomSheetRecyclerBinding.inflate(inflater, container, false)
return _binding?.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding.repliesRecyclerView.adapter = adapter
binding.repliesRecyclerView.layoutManager = LinearLayoutManager(
requireContext(),
LinearLayoutManager.VERTICAL,
false
)
binding.replyButton.setOnClickListener {
val context = requireContext()
ContextCompat.startActivity(
context,
Intent(context, MarkdownCreatorActivity::class.java)
.putExtra("type", "replyActivity")
.putExtra("parentId", activityId),
null
)
}
activityId = requireArguments().getInt("activityId")
loading(true)
lifecycleScope.launch(Dispatchers.IO) {
val response = Anilist.query.getReplies(activityId)
withContext(Dispatchers.Main) {
loading(false)
if (response != null) {
replies.clear()
replies.addAll(response.data.page.activityReplies)
adapter.update(replies.map { ActivityReplyItem(it, requireActivity()) { _, _ -> } })
} else {
snackString("Failed to load replies")
}
}
}
}
private fun loading(load: Boolean) {
binding.repliesRefresh.isVisible = load
binding.repliesRecyclerView.isVisible = !load
}
override fun onDestroyView() {
_binding = null
super.onDestroyView()
}
companion object {
fun newInstance(activityId: Int): RepliesBottomDialog {
return RepliesBottomDialog().apply {
arguments = Bundle().apply {
putInt("activityId", activityId)
}
}
}
}
}

View file

@ -14,6 +14,7 @@ import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.app.ActivityOptionsCompat import androidx.core.app.ActivityOptionsCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
import ani.dantotsu.R import ani.dantotsu.R
import ani.dantotsu.blurImage import ani.dantotsu.blurImage
@ -214,10 +215,6 @@ class Stories @JvmOverloads constructor(
timer.setOnTimerCompletedListener { timer.setOnTimerCompletedListener {
Logger.log("onAnimationEnd: $storyIndex") Logger.log("onAnimationEnd: $storyIndex")
if (storyIndex - 1 <= activityList.size) { if (storyIndex - 1 <= activityList.size) {
if (false) {
Logger.log("userClicked: $storyIndex")
userClicked = false
} else {
Logger.log("userNotClicked: $storyIndex") Logger.log("userNotClicked: $storyIndex")
if (storyIndex < activityList.size) { if (storyIndex < activityList.size) {
storyIndex += 1 storyIndex += 1
@ -227,7 +224,6 @@ class Stories @JvmOverloads constructor(
binding.androidStoriesLoadingView.visibility = View.GONE binding.androidStoriesLoadingView.visibility = View.GONE
onStoriesCompleted() onStoriesCompleted()
} }
}
} else { } else {
// on stories end // on stories end
binding.androidStoriesLoadingView.visibility = View.GONE binding.androidStoriesLoadingView.visibility = View.GONE
@ -447,6 +443,9 @@ class Stories @JvmOverloads constructor(
} }
val likeColor = ContextCompat.getColor(context, R.color.yt_red) val likeColor = ContextCompat.getColor(context, R.color.yt_red)
val notLikeColor = ContextCompat.getColor(context, R.color.bg_opp) val notLikeColor = ContextCompat.getColor(context, R.color.bg_opp)
binding.activityReplies.setOnClickListener {
RepliesBottomDialog.newInstance(story.id).show(activity.supportFragmentManager, "replies")
}
binding.activityLikeCount.text = story.likeCount.toString() binding.activityLikeCount.text = story.likeCount.toString()
binding.activityLike.setColorFilter(if (story.isLiked == true) likeColor else notLikeColor) binding.activityLike.setColorFilter(if (story.isLiked == true) likeColor else notLikeColor)
binding.activityLikeContainer.setOnClickListener { binding.activityLikeContainer.setOnClickListener {

View file

@ -54,8 +54,9 @@ class ActivityItem(
val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red) val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red)
val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp) val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp)
binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor) binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor)
binding.commentRepliesContainer.isVisible = activity.replyCount > 0 binding.commentTotalReplies.isVisible = activity.replyCount > 0
binding.commentRepliesContainer.setOnClickListener { binding.dot.isVisible = activity.replyCount > 0
binding.commentTotalReplies.setOnClickListener {
when (binding.activityReplies.visibility) { when (binding.activityReplies.visibility) {
View.GONE -> { View.GONE -> {
val replyItems = activity.replies?.map { val replyItems = activity.replies?.map {
@ -69,6 +70,16 @@ class ActivityItem(
repliesAdapter.addAll(replyItems) repliesAdapter.addAll(replyItems)
binding.activityReplies.visibility = View.VISIBLE binding.activityReplies.visibility = View.VISIBLE
binding.commentTotalReplies.setText(R.string.hide_replies) binding.commentTotalReplies.setText(R.string.hide_replies)
}
else -> {
repliesAdapter.clear()
binding.activityReplies.visibility = View.GONE
binding.commentTotalReplies.setText(R.string.view_replies)
}
}
}
if (activity.isLocked != true) { if (activity.isLocked != true) {
binding.commentReply.setOnClickListener { binding.commentReply.setOnClickListener {
val context = binding.root.context val context = binding.root.context
@ -84,16 +95,6 @@ class ActivityItem(
binding.commentReply.visibility = View.GONE binding.commentReply.visibility = View.GONE
binding.dot.visibility = View.GONE binding.dot.visibility = View.GONE
} }
}
else -> {
repliesAdapter.clear()
binding.activityReplies.visibility = View.GONE
binding.commentTotalReplies.setText(R.string.view_replies)
}
}
}
val userList = arrayListOf<User>() val userList = arrayListOf<User>()
activity.likes?.forEach { i -> activity.likes?.forEach { i ->
userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage)) userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage))

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="64dp"
android:fontFamily="@font/poppins_bold"
android:gravity="center_vertical"
android:paddingHorizontal="32dp"
android:text="@string/replies"
android:textColor="?attr/colorPrimary"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/replyButton"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="16dp"
android:contentDescription="@string/reply"
android:fontFamily="@font/poppins_bold"
android:gravity="center_vertical"
android:src="@drawable/ic_add"
app:layout_constraintBottom_toBottomOf="@+id/title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/title"
app:tint="?attr/colorPrimary" />
<ProgressBar
android:id="@+id/repliesRefresh"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginTop="32dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/repliesRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="16dp"
app:layout_constraintTop_toBottomOf="@+id/replyButton" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -176,8 +176,18 @@
tools:srcCompat="@tools:sample/backgrounds/scenic" /> tools:srcCompat="@tools:sample/backgrounds/scenic" />
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
<ImageView
android:id="@+id/activityReplies"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:src="@drawable/ic_round_comment_24"
app:layout_constraintBottom_toTopOf="@+id/linearLayout"
app:layout_constraintEnd_toEndOf="@+id/linearLayout"
tools:ignore="ContentDescription" />
<LinearLayout <LinearLayout
android:id="@+id/linearLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
@ -204,7 +214,6 @@
tools:ignore="SpUsage" tools:ignore="SpUsage"
tools:text="@string/slogan" /> tools:text="@string/slogan" />
<LinearLayout <LinearLayout
android:id="@+id/activityLikeContainer" android:id="@+id/activityLikeContainer"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -221,12 +230,13 @@
android:fontFamily="@font/poppins_semi_bold" android:fontFamily="@font/poppins_semi_bold"
android:textSize="15sp" android:textSize="15sp"
tools:text="12" /> tools:text="12" />
<ImageView <ImageView
android:id="@+id/activityLike" android:id="@+id/activityLike"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_gravity="center|end" android:layout_gravity="center|end"
android:layout_marginStart="12dp"
android:src="@drawable/ic_round_favorite_24" android:src="@drawable/ic_round_favorite_24"
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
</LinearLayout> </LinearLayout>

View file

@ -987,4 +987,5 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<string name="preview">Preview</string> <string name="preview">Preview</string>
<string name="cannot_be_empty">Text cannot be empty</string> <string name="cannot_be_empty">Text cannot be empty</string>
<string name="reply">Reply</string> <string name="reply">Reply</string>
<string name="replies">Replies</string>
</resources> </resources>