From 001c384d1171c0c72b167b336ef3df01b49fe6d7 Mon Sep 17 00:00:00 2001 From: rebelonion <87634197+rebelonion@users.noreply.github.com> Date: Sun, 12 May 2024 21:44:10 -0500 Subject: [PATCH] feat: replies in stories --- .../connections/anilist/AnilistQueries.kt | 12 ++- .../dantotsu/connections/anilist/api/Feed.kt | 18 ++++ .../home/status/RepliesBottomDialog.kt | 94 +++++++++++++++++++ .../java/ani/dantotsu/home/status/Stories.kt | 23 +++-- .../dantotsu/profile/activity/ActivityItem.kt | 35 +++---- .../main/res/layout/bottom_sheet_recycler.xml | 55 +++++++++++ app/src/main/res/layout/fragment_status.xml | 14 ++- app/src/main/res/values/strings.xml | 1 + 8 files changed, 220 insertions(+), 32 deletions(-) create mode 100644 app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt create mode 100644 app/src/main/res/layout/bottom_sheet_recycler.xml diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt index bd779e00..e98966e6 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt @@ -11,6 +11,7 @@ import ani.dantotsu.connections.anilist.api.FuzzyDate import ani.dantotsu.connections.anilist.api.NotificationResponse import ani.dantotsu.connections.anilist.api.Page import ani.dantotsu.connections.anilist.api.Query +import ani.dantotsu.connections.anilist.api.ReplyResponse import ani.dantotsu.connections.anilist.api.ToggleLike import ani.dantotsu.currContext import ani.dantotsu.isOnline @@ -1612,8 +1613,17 @@ Page(page:$page,perPage:50) { 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 { - 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 { diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt index 7e7c786d..03ec0c46 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Feed.kt @@ -74,6 +74,24 @@ data class Activity( val likes: List?, ) : 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 +) : java.io.Serializable + @Serializable data class ActivityReply( @SerialName("id") diff --git a/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt b/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt new file mode 100644 index 00000000..69b5738a --- /dev/null +++ b/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt @@ -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 = 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) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/home/status/Stories.kt b/app/src/main/java/ani/dantotsu/home/status/Stories.kt index 0b166da9..d7731562 100644 --- a/app/src/main/java/ani/dantotsu/home/status/Stories.kt +++ b/app/src/main/java/ani/dantotsu/home/status/Stories.kt @@ -14,6 +14,7 @@ import androidx.constraintlayout.widget.ConstraintSet import androidx.core.app.ActivityOptionsCompat import androidx.core.content.ContextCompat import androidx.core.view.ViewCompat +import androidx.core.view.isVisible import androidx.fragment.app.FragmentActivity import ani.dantotsu.R import ani.dantotsu.blurImage @@ -214,19 +215,14 @@ class Stories @JvmOverloads constructor( timer.setOnTimerCompletedListener { Logger.log("onAnimationEnd: $storyIndex") if (storyIndex - 1 <= activityList.size) { - if (false) { - Logger.log("userClicked: $storyIndex") - userClicked = false + Logger.log("userNotClicked: $storyIndex") + if (storyIndex < activityList.size) { + storyIndex += 1 + showStory() } else { - Logger.log("userNotClicked: $storyIndex") - if (storyIndex < activityList.size) { - storyIndex += 1 - showStory() - } else { - // on stories end - binding.androidStoriesLoadingView.visibility = View.GONE - onStoriesCompleted() - } + // on stories end + binding.androidStoriesLoadingView.visibility = View.GONE + onStoriesCompleted() } } else { // on stories end @@ -447,6 +443,9 @@ class Stories @JvmOverloads constructor( } val likeColor = ContextCompat.getColor(context, R.color.yt_red) 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.activityLike.setColorFilter(if (story.isLiked == true) likeColor else notLikeColor) binding.activityLikeContainer.setOnClickListener { diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt index da8f770e..f027b276 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt @@ -54,8 +54,9 @@ class ActivityItem( val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red) val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp) binding.activityLike.setColorFilter(if (activity.isLiked == true) likeColor else notLikeColor) - binding.commentRepliesContainer.isVisible = activity.replyCount > 0 - binding.commentRepliesContainer.setOnClickListener { + binding.commentTotalReplies.isVisible = activity.replyCount > 0 + binding.dot.isVisible = activity.replyCount > 0 + binding.commentTotalReplies.setOnClickListener { when (binding.activityReplies.visibility) { View.GONE -> { val replyItems = activity.replies?.map { @@ -69,21 +70,6 @@ class ActivityItem( repliesAdapter.addAll(replyItems) binding.activityReplies.visibility = View.VISIBLE binding.commentTotalReplies.setText(R.string.hide_replies) - if (activity.isLocked != true) { - binding.commentReply.setOnClickListener { - val context = binding.root.context - ContextCompat.startActivity( - context, - Intent(context, MarkdownCreatorActivity::class.java) - .putExtra("type", "replyActivity") - .putExtra("parentId", activity.id), - null - ) - } - } else { - binding.commentReply.visibility = View.GONE - binding.dot.visibility = View.GONE - } } else -> { @@ -94,6 +80,21 @@ class ActivityItem( } } } + if (activity.isLocked != true) { + binding.commentReply.setOnClickListener { + val context = binding.root.context + ContextCompat.startActivity( + context, + Intent(context, MarkdownCreatorActivity::class.java) + .putExtra("type", "replyActivity") + .putExtra("parentId", activity.id), + null + ) + } + } else { + binding.commentReply.visibility = View.GONE + binding.dot.visibility = View.GONE + } val userList = arrayListOf() activity.likes?.forEach { i -> userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage)) diff --git a/app/src/main/res/layout/bottom_sheet_recycler.xml b/app/src/main/res/layout/bottom_sheet_recycler.xml new file mode 100644 index 00000000..90c6e4b6 --- /dev/null +++ b/app/src/main/res/layout/bottom_sheet_recycler.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_status.xml b/app/src/main/res/layout/fragment_status.xml index de59e3b0..6c8cc185 100644 --- a/app/src/main/res/layout/fragment_status.xml +++ b/app/src/main/res/layout/fragment_status.xml @@ -176,8 +176,18 @@ tools:srcCompat="@tools:sample/backgrounds/scenic" /> + - + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e9ad5e6c..e57f4367 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -987,4 +987,5 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc Preview Text cannot be empty Reply + Replies