diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt index a8bd890419..88e88e41bf 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistMutations.kt @@ -3,9 +3,9 @@ package ani.dantotsu.connections.anilist import ani.dantotsu.connections.anilist.Anilist.executeQuery import ani.dantotsu.connections.anilist.api.FuzzyDate import ani.dantotsu.connections.anilist.api.Query +import ani.dantotsu.connections.anilist.api.ToggleLike import ani.dantotsu.currContext import com.google.gson.Gson -import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject class AnilistMutations { @@ -76,38 +76,66 @@ class AnilistMutations { suspend fun rateReview(reviewId: Int, rating: String): Query.RateReviewResponse? { - val query = "mutation{RateReview(reviewId:$reviewId,rating:$rating){id mediaId mediaType summary body(asHtml:true)rating ratingAmount userRating score private siteUrl createdAt updatedAt user{id name bannerImage avatar{medium large}}}}" + val query = + "mutation{RateReview(reviewId:$reviewId,rating:$rating){id mediaId mediaType summary body(asHtml:true)rating ratingAmount userRating score private siteUrl createdAt updatedAt user{id name bannerImage avatar{medium large}}}}" return executeQuery(query) } - suspend fun postActivity(text:String): String { + suspend fun toggleFollow(id: Int): Query.ToggleFollow? { + return executeQuery( + """mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}""" + ) + } + + suspend fun toggleLike(id: Int, type: String): ToggleLike? { + return executeQuery( + """mutation Like{ToggleLikeV2(id:$id,type:$type){__typename}}""" + ) + } + + suspend fun postActivity(text: String, edit : Int? = null): String { val encodedText = text.stringSanitizer() - val query = "mutation{SaveTextActivity(text:$encodedText){siteUrl}}" + val query = "mutation{SaveTextActivity(${if (edit != null) "id:$edit," else ""} text:$encodedText){siteUrl}}" + val result = executeQuery(query) + val errors = result?.get("errors") + return errors?.toString() + ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") + } + suspend fun postReply(activityId: Int, text: String, edit: Int? = null ): String { + val encodedText = text.stringSanitizer() + val query = "mutation{SaveActivityReply(${if (edit != null) "id:$edit," else ""} activityId:$activityId,text:$encodedText){id}}" val result = executeQuery(query) val errors = result?.get("errors") return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") } - suspend fun postReview(summary: String, body: String, mediaId: Int, score: Int): String { val encodedSummary = summary.stringSanitizer() val encodedBody = body.stringSanitizer() - val query = "mutation{SaveReview(mediaId:$mediaId,summary:$encodedSummary,body:$encodedBody,score:$score){siteUrl}}" + val query = + "mutation{SaveReview(mediaId:$mediaId,summary:$encodedSummary,body:$encodedBody,score:$score){siteUrl}}" val result = executeQuery(query) val errors = result?.get("errors") return errors?.toString() ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") } - suspend fun postReply(activityId: Int, text: String): String { - val encodedText = text.stringSanitizer() - val query = "mutation{SaveActivityReply(activityId:$activityId,text:$encodedText){id}}" + suspend fun deleteActivityReply(activityId: Int): Boolean { + val query = "mutation{DeleteActivityReply(id:$activityId){deleted}}" val result = executeQuery(query) val errors = result?.get("errors") - return errors?.toString() - ?: (currContext()?.getString(ani.dantotsu.R.string.success) ?: "Success") + return errors == null } + suspend fun deleteActivity(activityId: Int): Boolean { + val query = "mutation{DeleteActivity(id:$activityId){deleted}}" + val result = executeQuery(query) + val errors = result?.get("errors") + return errors == null + } + + + private fun String.stringSanitizer(): String { val sb = StringBuilder() var i = 0 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 480f3c7dff..23ee295a2c 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt @@ -1548,18 +1548,6 @@ Page(page:$page,perPage:50) { ) } - suspend fun toggleFollow(id: Int): Query.ToggleFollow? { - return executeQuery( - """mutation{ToggleFollow(userId:$id){id, isFollowing, isFollower}}""" - ) - } - - suspend fun toggleLike(id: Int, type: String): ToggleLike? { - return executeQuery( - """mutation Like{ToggleLikeV2(id:$id,type:$type){__typename}}""" - ) - } - suspend fun getUserProfile(id: Int): Query.UserProfileResponse? { return executeQuery( """{followerPage:Page{followers(userId:$id){id}pageInfo{total}}followingPage:Page{following(userId:$id){id}pageInfo{total}}user:User(id:$id){id name about(asHtml:true)avatar{medium large}bannerImage isFollowing isFollower isBlocked favourites{anime{nodes{id coverImage{extraLarge large medium color}}}manga{nodes{id coverImage{extraLarge large medium color}}}characters{nodes{id name{first middle last full native alternative userPreferred}image{large medium}isFavourite}}staff{nodes{id name{first middle last full native alternative userPreferred}image{large medium}isFavourite}}studios{nodes{id name isFavourite}}}statistics{anime{count meanScore standardDeviation minutesWatched episodesWatched chaptersRead volumesRead}manga{count meanScore standardDeviation minutesWatched episodesWatched chaptersRead volumesRead}}siteUrl}}""", @@ -1618,11 +1606,13 @@ Page(page:$page,perPage:50) { suspend fun getNotifications( id: Int, page: Int = 1, - resetNotification: Boolean = true + resetNotification: Boolean = true, + type: Boolean? = null ): NotificationResponse? { + val type_in = "type_in:[AIRING,MEDIA_MERGE,MEDIA_DELETION,MEDIA_DATA_CHANGE]" val reset = if (resetNotification) "true" else "false" val res = executeQuery( - """{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){pageInfo{currentPage,hasNextPage}notifications(resetNotificationCount:$reset){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""", + """{User(id:$id){unreadNotificationCount}Page(page:$page,perPage:$ITEMS_PER_PAGE){pageInfo{currentPage,hasNextPage}notifications(resetNotificationCount:$reset , ${if (type == true) type_in else ""}){__typename...on AiringNotification{id,type,animeId,episode,contexts,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}},}...on FollowingNotification{id,userId,type,context,createdAt,user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMessageNotification{id,userId,type,activityId,context,createdAt,message{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityMentionNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplySubscribedNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ActivityReplyLikeNotification{id,userId,type,activityId,context,createdAt,activity{__typename}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentMentionNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentReplyNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentSubscribedNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadCommentLikeNotification{id,userId,type,commentId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on ThreadLikeNotification{id,userId,type,threadId,context,createdAt,thread{id}comment{id}user{id,name,bannerImage,avatar{medium,large,}}}...on RelatedMediaAdditionNotification{id,type,context,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDataChangeNotification{id,type,mediaId,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaMergeNotification{id,type,mediaId,deletedMediaTitles,context,reason,createdAt,media{id,title{romaji,english,native,userPreferred}bannerImage,coverImage{medium,large}}}...on MediaDeletionNotification{id,type,deletedMediaTitle,context,reason,createdAt,}}}}""", force = true ) if (res != null && resetNotification) { diff --git a/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt b/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt index e262f6ff29..218bf7fe58 100644 --- a/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt +++ b/app/src/main/java/ani/dantotsu/home/status/RepliesBottomDialog.kt @@ -74,7 +74,9 @@ class RepliesBottomDialog : BottomSheetDialogFragment() { replies.map { ActivityReplyItem( it, + activityId, requireActivity(), + adapter, clickCallback = { int, _ -> onClick(int) } @@ -109,7 +111,6 @@ class RepliesBottomDialog : BottomSheetDialogFragment() { super.onResume() loading(true) lifecycleScope.launch(Dispatchers.IO) { - delay(2000) loadData() } } 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 9f1638579c..c8df6d9a71 100644 --- a/app/src/main/java/ani/dantotsu/home/status/Stories.kt +++ b/app/src/main/java/ani/dantotsu/home/status/Stories.kt @@ -422,14 +422,14 @@ class Stories @JvmOverloads constructor( } val likeColor = ContextCompat.getColor(context, R.color.yt_red) val notLikeColor = ContextCompat.getColor(context, R.color.bg_opp) + binding.replyCount.text = story.replyCount.toString() + binding.activityReplies.setColorFilter(ContextCompat.getColor(context, R.color.bg_opp)) binding.activityRepliesContainer.setOnClickListener { RepliesBottomDialog.newInstance(story.id) .show(activity.supportFragmentManager, "replies") } binding.activityLike.setColorFilter(if (story.isLiked == true) likeColor else notLikeColor) - binding.replyCount.text = story.replyCount.toString() binding.activityLikeCount.text = story.likeCount.toString() - binding.activityReplies.setColorFilter(ContextCompat.getColor(context, R.color.bg_opp)) binding.activityLikeContainer.setOnClickListener { like() } @@ -451,7 +451,7 @@ class Stories @JvmOverloads constructor( val notLikeColor = ContextCompat.getColor(context, R.color.bg_opp) val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) scope.launch { - val res = Anilist.query.toggleLike(story.id, "ACTIVITY") + val res = Anilist.mutation.toggleLike(story.id, "ACTIVITY") withContext(Dispatchers.Main) { if (res != null) { if (story.isLiked == true) { diff --git a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt index aef3f4c33b..6c8c88bcf9 100644 --- a/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/ProfileActivity.kt @@ -136,7 +136,7 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene followButton.setOnClickListener { lifecycleScope.launch(Dispatchers.IO) { - val res = Anilist.query.toggleFollow(user.id) + val res = Anilist.mutation.toggleFollow(user.id) if (res?.data?.toggleFollow != null) { withContext(Dispatchers.Main) { snackString(R.string.success) @@ -325,7 +325,7 @@ class ProfileActivity : AppCompatActivity(), AppBarLayout.OnOffsetChangedListene override fun getItemCount(): Int = 3 override fun createFragment(position: Int): Fragment = when (position) { 0 -> ProfileFragment.newInstance(user) - 1 -> ActivityFragment(ActivityType.OTHER_USER, user.id) + 1 -> ActivityFragment.newInstance(ActivityType.OTHER_USER, user.id) 2 -> StatsFragment.newInstance(user) else -> ProfileFragment.newInstance(user) } diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityFragment.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityFragment.kt index cad302916f..78f234d4be 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityFragment.kt @@ -21,13 +21,13 @@ import ani.dantotsu.navBarHeight import ani.dantotsu.profile.ProfileActivity import ani.dantotsu.setBaseline import com.xwray.groupie.GroupieAdapter +import eu.kanade.tachiyomi.util.system.getSerializableCompat import kotlinx.coroutines.launch -class ActivityFragment( - var type: ActivityType, - val userId: Int? = null, - var activityId: Int? = null, -) : Fragment() { +class ActivityFragment : Fragment() { + private lateinit var type: ActivityType + private var userId: Int? = null + private var activityId: Int? = null private lateinit var binding: FragmentFeedBinding private var adapter: GroupieAdapter = GroupieAdapter() private var page: Int = 1 @@ -43,15 +43,13 @@ class ActivityFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val navBar = if (userId != null) { - (activity as ProfileActivity).navBar - } else { - (activity as FeedActivity).navBar - } - binding.listRecyclerView.setBaseline(navBar) + type = arguments?.getSerializableCompat("type") as ActivityType + userId = arguments?.getInt("userId") + activityId = arguments?.getInt("activityId") binding.listRecyclerView.adapter = adapter binding.listRecyclerView.layoutManager = LinearLayoutManager(context) binding.listProgressBar.isVisible = true + binding.feedRefresh.updateLayoutParams { bottomMargin = navBarHeight } @@ -94,7 +92,7 @@ class ActivityFragment( ActivityType.OTHER_USER -> getActivities(userId = userId) ActivityType.ONE -> getActivities(activityId = activityId) } - adapter.addAll(list.map { ActivityItem(it, ::onActivityClick, requireActivity()) }) + adapter.addAll(list.map { ActivityItem(it, ::onActivityClick, adapter ,requireActivity()) }) } private suspend fun getActivities( @@ -142,12 +140,7 @@ class ActivityFragment( super.onResume() if (this::binding.isInitialized) { binding.root.requestLayout() - val navBar = if (userId != null) { - (activity as ProfileActivity).navBar - } else { - (activity as FeedActivity).navBar - } - binding.listRecyclerView.setBaseline(navBar) + } } @@ -155,5 +148,15 @@ class ActivityFragment( enum class ActivityType { GLOBAL, USER, OTHER_USER, ONE } + + fun newInstance(type: ActivityType, userId: Int? = null, activityId: Int? = null): ActivityFragment { + return ActivityFragment().apply { + arguments = Bundle().apply { + putSerializable("type", type) + userId?.let { putInt("userId", it) } + activityId?.let { putInt("activityId", it) } + } + } + } } } \ No newline at end of file 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 f027b27699..f7375ddda9 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityItem.kt @@ -12,6 +12,7 @@ import ani.dantotsu.buildMarkwon import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.api.Activity import ani.dantotsu.databinding.ItemActivityBinding +import ani.dantotsu.home.status.RepliesBottomDialog import ani.dantotsu.loadImage import ani.dantotsu.profile.User import ani.dantotsu.profile.UsersDialogFragment @@ -30,22 +31,16 @@ import kotlinx.coroutines.withContext class ActivityItem( private val activity: Activity, val clickCallback: (Int, type: String) -> Unit, + private val parentAdapter: GroupieAdapter, private val fragActivity: FragmentActivity ) : BindableItem() { private lateinit var binding: ItemActivityBinding - private lateinit var repliesAdapter: GroupieAdapter override fun bind(viewBinding: ItemActivityBinding, position: Int) { binding = viewBinding + val context = binding.root.context + val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) setAnimation(binding.root.context, binding.root) - - repliesAdapter = GroupieAdapter() - binding.activityReplies.adapter = repliesAdapter - binding.activityReplies.layoutManager = LinearLayoutManager( - binding.root.context, - LinearLayoutManager.VERTICAL, - false - ) binding.activityUserName.text = activity.user?.name ?: activity.messenger?.name binding.activityUserAvatar.loadImage( activity.user?.avatar?.medium ?: activity.messenger?.avatar?.medium @@ -54,51 +49,16 @@ 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.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 { - ActivityReplyItem(it,fragActivity) { id, type -> - clickCallback( - id, - type - ) - } - } ?: emptyList() - repliesAdapter.addAll(replyItems) - binding.activityReplies.visibility = View.VISIBLE - 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) { - 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)) } + binding.activityRepliesContainer.setOnClickListener { + RepliesBottomDialog.newInstance(activity.id) + .show(fragActivity.supportFragmentManager, "replies") + } + binding.replyCount.text = activity.replyCount.toString() + binding.activityReplies.setColorFilter(ContextCompat.getColor(binding.root.context, R.color.bg_opp)) binding.activityLikeContainer.setOnLongClickListener { UsersDialogFragment().apply { userList(userList) @@ -108,9 +68,9 @@ class ActivityItem( } binding.activityLikeCount.text = (activity.likeCount ?: 0).toString() binding.activityLikeContainer.setOnClickListener { - val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) + scope.launch { - val res = Anilist.query.toggleLike(activity.id, "ACTIVITY") + val res = Anilist.mutation.toggleLike(activity.id, "ACTIVITY") withContext(Dispatchers.Main) { if (res != null) { @@ -129,7 +89,20 @@ class ActivityItem( } } } - val context = binding.root.context + binding.activityDelete.isVisible = activity.userId == Anilist.userid + binding.activityDelete.setOnClickListener { + scope.launch { + val res = Anilist.mutation.deleteActivity(activity.id) + withContext(Dispatchers.Main) { + if (res) { + snackString("Deleted activity") + parentAdapter.remove(this@ActivityItem) + } else { + snackString("Failed to delete activity") + } + } + } + } when (activity.typename) { "ListActivity" -> { val cover = activity.media?.coverImage?.large @@ -156,6 +129,7 @@ class ActivityItem( binding.activityMediaName.setOnClickListener { clickCallback(activity.media?.id ?: -1, "MEDIA") } + binding.activityEdit.isVisible = false } "TextActivity" -> { @@ -174,6 +148,17 @@ class ActivityItem( binding.activityUserName.setOnClickListener { clickCallback(activity.userId ?: -1, "USER") } + binding.activityEdit.isVisible = activity.userId == Anilist.userid + binding.activityEdit.setOnClickListener { + ContextCompat.startActivity( + context, + Intent(context, MarkdownCreatorActivity::class.java) + .putExtra("type", "activity") + .putExtra("other", activity.text) + .putExtra("edit", activity.id), + null + ) + } } "MessageActivity" -> { @@ -192,6 +177,7 @@ class ActivityItem( binding.activityUserName.setOnClickListener { clickCallback(activity.messengerId ?: -1, "USER") } + binding.activityEdit.isVisible = false } } } diff --git a/app/src/main/java/ani/dantotsu/profile/activity/ActivityReplyItem.kt b/app/src/main/java/ani/dantotsu/profile/activity/ActivityReplyItem.kt index 21befe050f..1f9039d1ca 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/ActivityReplyItem.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/ActivityReplyItem.kt @@ -1,7 +1,9 @@ package ani.dantotsu.profile.activity +import android.content.Intent import android.view.View import androidx.core.content.ContextCompat +import androidx.core.view.isVisible import androidx.fragment.app.FragmentActivity import ani.dantotsu.R import ani.dantotsu.buildMarkwon @@ -13,6 +15,8 @@ import ani.dantotsu.profile.User import ani.dantotsu.profile.UsersDialogFragment import ani.dantotsu.snackString import ani.dantotsu.util.AniMarkdown.Companion.getBasicAniHTML +import ani.dantotsu.util.MarkdownCreatorActivity +import com.xwray.groupie.GroupieAdapter import com.xwray.groupie.viewbinding.BindableItem import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -22,23 +26,27 @@ import kotlinx.coroutines.withContext class ActivityReplyItem( private val reply: ActivityReply, + private val parentId : Int, private val fragActivity: FragmentActivity, + private val parentAdapter: GroupieAdapter, private val clickCallback: (Int, type: String) -> Unit, ) : BindableItem() { private lateinit var binding: ItemActivityReplyBinding override fun bind(viewBinding: ItemActivityReplyBinding, position: Int) { binding = viewBinding - + val context = binding.root.context + val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) binding.activityUserAvatar.loadImage(reply.user.avatar?.medium) binding.activityUserName.text = reply.user.name binding.activityTime.text = ActivityItemBuilder.getDateTime(reply.createdAt) binding.activityLikeCount.text = reply.likeCount.toString() - val likeColor = ContextCompat.getColor(binding.root.context, R.color.yt_red) - val notLikeColor = ContextCompat.getColor(binding.root.context, R.color.bg_opp) + val likeColor = ContextCompat.getColor(context, R.color.yt_red) + val notLikeColor = ContextCompat.getColor(context, R.color.bg_opp) binding.activityLike.setColorFilter(if (reply.isLiked) likeColor else notLikeColor) - val markwon = buildMarkwon(binding.root.context) + val markwon = buildMarkwon(context) markwon.setMarkdown(binding.activityContent, getBasicAniHTML(reply.text)) + val userList = arrayListOf() reply.likes?.forEach { i -> userList.add(User(i.id, i.name.toString(), i.avatar?.medium, i.bannerImage)) @@ -51,9 +59,8 @@ class ActivityReplyItem( true } binding.activityLikeContainer.setOnClickListener { - val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) scope.launch { - val res = Anilist.query.toggleLike(reply.id, "ACTIVITY_REPLY") + val res = Anilist.mutation.toggleLike(reply.id, "ACTIVITY_REPLY") withContext(Dispatchers.Main) { if (res != null) { if (reply.isLiked) { @@ -71,6 +78,42 @@ class ActivityReplyItem( } } } + binding.activityReply.setOnClickListener { + ContextCompat.startActivity( + context, + Intent(context, MarkdownCreatorActivity::class.java) + .putExtra("type", "replyActivity") + .putExtra("parentId", parentId) + .putExtra("other", "@${reply.user.name} "), + null + ) + } + binding.activityEdit.isVisible = reply.userId == Anilist.userid + binding.activityEdit.setOnClickListener { + ContextCompat.startActivity( + context, + Intent(context, MarkdownCreatorActivity::class.java) + .putExtra("type", "replyActivity") + .putExtra("parentId", parentId) + .putExtra("other", reply.text) + .putExtra("edit", reply.id), + null + ) + } + binding.activityDelete.isVisible = reply.userId == Anilist.userid + binding.activityDelete.setOnClickListener { + scope.launch { + val res = Anilist.mutation.deleteActivityReply(reply.id) + withContext(Dispatchers.Main) { + if (res) { + snackString("Deleted") + parentAdapter.remove(this@ActivityReplyItem) + } else { + snackString("Failed to delete") + } + } + } + } binding.activityAvatarContainer.setOnClickListener { clickCallback(reply.userId, "USER") diff --git a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt index 1b2079b4ab..45122fecd8 100644 --- a/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/activity/FeedActivity.kt @@ -47,6 +47,7 @@ class FeedActivity : AppCompatActivity() { Pair(R.drawable.ic_globe_24, "Global"), ) tabs.forEach { (icon, title) -> navBar.addTab(navBar.createTab(icon, title)) } + binding.notificationBack.setOnClickListener { onBackPressedDispatcher.onBackPressed() } val getOne = intent.getIntExtra("activityId", -1) if (getOne != -1) { navBar.visibility = View.GONE } @@ -87,8 +88,8 @@ class FeedActivity : AppCompatActivity() { override fun createFragment(position: Int): Fragment { return when (position) { - 0 -> ActivityFragment(if (activityId != -1) ActivityType.ONE else ActivityType.USER, activityId = activityId) - else -> ActivityFragment(ActivityType.GLOBAL) + 0 -> ActivityFragment.newInstance(if (activityId != -1) ActivityType.ONE else ActivityType.USER, activityId = activityId) + else -> ActivityFragment.newInstance(ActivityType.GLOBAL) } } } diff --git a/app/src/main/java/ani/dantotsu/profile/notification/NotificationActivity.kt b/app/src/main/java/ani/dantotsu/profile/notification/NotificationActivity.kt index ea0de673bb..e1e77cf39b 100644 --- a/app/src/main/java/ani/dantotsu/profile/notification/NotificationActivity.kt +++ b/app/src/main/java/ani/dantotsu/profile/notification/NotificationActivity.kt @@ -84,11 +84,11 @@ class NotificationActivity : AppCompatActivity() { override fun getItemCount(): Int = if (id != -1) 1 else 4 override fun createFragment(position: Int): Fragment = when (position) { - 0 -> NotificationFragment(if (id != -1) NotificationType.ONE else NotificationType.MEDIA, id) - 1 -> NotificationFragment(NotificationType.USER) - 2 -> NotificationFragment(NotificationType.SUBSCRIPTION) - 3 -> NotificationFragment(NotificationType.COMMENT) - else -> NotificationFragment(NotificationType.MEDIA) + 0 -> NotificationFragment.newInstance(if (id != -1) NotificationType.ONE else NotificationType.MEDIA, id) + 1 -> NotificationFragment.newInstance(NotificationType.USER) + 2 -> NotificationFragment.newInstance(NotificationType.SUBSCRIPTION) + 3 -> NotificationFragment.newInstance(NotificationType.COMMENT) + else -> NotificationFragment.newInstance(NotificationType.MEDIA) } } } diff --git a/app/src/main/java/ani/dantotsu/profile/notification/NotificationFragment.kt b/app/src/main/java/ani/dantotsu/profile/notification/NotificationFragment.kt index 1c6b827e45..2e6f2d2886 100644 --- a/app/src/main/java/ani/dantotsu/profile/notification/NotificationFragment.kt +++ b/app/src/main/java/ani/dantotsu/profile/notification/NotificationFragment.kt @@ -7,18 +7,15 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.core.view.isVisible -import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import androidx.webkit.internal.ApiFeature.N import ani.dantotsu.R import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.api.Notification import ani.dantotsu.databinding.FragmentNotificationsBinding import ani.dantotsu.media.MediaDetailsActivity -import ani.dantotsu.navBarHeight import ani.dantotsu.notifications.comment.CommentStore import ani.dantotsu.notifications.subscription.SubscriptionStore import ani.dantotsu.profile.ProfileActivity @@ -27,13 +24,13 @@ import ani.dantotsu.setBaseline import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import com.xwray.groupie.GroupieAdapter +import eu.kanade.tachiyomi.util.system.getSerializableCompat import kotlinx.coroutines.launch -class NotificationFragment( - val type: NotificationType, - val getID: Int = -1 -) : Fragment() { +class NotificationFragment : Fragment() { + private lateinit var type : NotificationType + private var getID : Int = -1 private lateinit var binding: FragmentNotificationsBinding private var adapter: GroupieAdapter = GroupieAdapter() private var currentPage = 1 @@ -49,14 +46,11 @@ class NotificationFragment( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - val navbar = (activity as NotificationActivity).navBar - binding.notificationRecyclerView.setBaseline(navbar) + type = arguments?.getSerializableCompat("type") as NotificationType + getID = arguments?.getInt("id") ?: -1 binding.notificationRecyclerView.adapter = adapter binding.notificationRecyclerView.layoutManager = LinearLayoutManager(context) binding.notificationProgressBar.isVisible = true - binding.notificationRefresh.updateLayoutParams { - bottomMargin = navBarHeight - } binding.emptyTextView.text = getString(R.string.no_notifications) lifecycleScope.launch { getList() @@ -92,7 +86,7 @@ class NotificationFragment( private suspend fun getList() { val list = when (type) { NotificationType.ONE -> getNotificationsFiltered(false) { it.id == getID } - NotificationType.MEDIA -> getNotificationsFiltered { it.media != null } + NotificationType.MEDIA -> getNotificationsFiltered(type = true) { it.media != null } NotificationType.USER -> getNotificationsFiltered { it.media == null } NotificationType.SUBSCRIPTION -> getSubscriptions() NotificationType.COMMENT -> getComments() @@ -102,11 +96,12 @@ class NotificationFragment( private suspend fun getNotificationsFiltered( reset: Boolean = true, + type: Boolean? = null, filter: (Notification) -> Boolean ): List { val userId = Anilist.userid ?: PrefManager.getVal(PrefName.AnilistUserId).toIntOrNull() ?: 0 - val res = Anilist.query.getNotifications(userId, currentPage, reset)?.data?.page + val res = Anilist.query.getNotifications(userId, currentPage, reset, type)?.data?.page currentPage = res?.pageInfo?.currentPage?.plus(1) ?: 1 hasNextPage = res?.pageInfo?.hasNextPage ?: false return res?.notifications?.filter(filter) ?: listOf() @@ -223,6 +218,15 @@ class NotificationFragment( enum class NotificationType { MEDIA, USER, SUBSCRIPTION, COMMENT, ONE } + + fun newInstance(type: NotificationType, id: Int = -1): NotificationFragment { + return NotificationFragment().apply { + arguments = Bundle().apply { + putSerializable("type", type) + putInt("id", id) + } + } + } } } \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/util/MarkdownCreatorActivity.kt b/app/src/main/java/ani/dantotsu/util/MarkdownCreatorActivity.kt index 9772bf63d5..1f02170412 100644 --- a/app/src/main/java/ani/dantotsu/util/MarkdownCreatorActivity.kt +++ b/app/src/main/java/ani/dantotsu/util/MarkdownCreatorActivity.kt @@ -24,7 +24,9 @@ class MarkdownCreatorActivity : AppCompatActivity() { private lateinit var binding: ActivityMarkdownCreatorBinding private lateinit var type: String private var text: String = "" + var ping: String? = null private var parentId: Int = 0 + @OptIn(DelicateCoroutinesApi::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -38,6 +40,7 @@ class MarkdownCreatorActivity : AppCompatActivity() { bottomMargin += navBarHeight } setContentView(binding.root) + if (intent.hasExtra("type")) { type = intent.getStringExtra("type")!! } else { @@ -57,8 +60,11 @@ class MarkdownCreatorActivity : AppCompatActivity() { } getString(R.string.create_new_reply) } + else -> "" } + ping = intent.getStringExtra("other") + text = ping ?: "" binding.editText.setText(text) binding.editText.addTextChangedListener { if (!binding.markdownCreatorPreviewCheckbox.isChecked) { @@ -86,15 +92,26 @@ class MarkdownCreatorActivity : AppCompatActivity() { setMessage(R.string.post_to_anilist_warning) setPosButton(R.string.ok) { launchIO { + val editId = intent.getIntExtra("edit", -1) + val isEdit = editId != -1 val success = when (type) { - "activity" -> Anilist.mutation.postActivity(text) + "activity" -> if (isEdit) { + Anilist.mutation.postActivity(text, editId) + } else { + Anilist.mutation.postActivity(text) + } //"review" -> Anilist.mutation.postReview(text) - "replyActivity" -> Anilist.mutation.postReply(parentId, text) + "replyActivity" -> if (isEdit) { + Anilist.mutation.postReply(parentId, text, editId) + } else { + Anilist.mutation.postReply(parentId, text) + } + else -> "Error: Unknown type" } toast(success) + finish() } - onBackPressedDispatcher.onBackPressed() } setNeutralButton(R.string.open_rules) { openLinkInBrowser("https://anilist.co/forum/thread/14") diff --git a/app/src/main/res/layout/fragment_notifications.xml b/app/src/main/res/layout/fragment_notifications.xml index 21a2cb731e..a5c0162544 100644 --- a/app/src/main/res/layout/fragment_notifications.xml +++ b/app/src/main/res/layout/fragment_notifications.xml @@ -58,7 +58,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:layout_marginBottom="32dp" android:visibility="gone" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_activity.xml b/app/src/main/res/layout/item_activity.xml index ccbdb634f0..3cce78a41c 100644 --- a/app/src/main/res/layout/item_activity.xml +++ b/app/src/main/res/layout/item_activity.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="16dp" + android:layout_marginTop="24dp" android:background="?attr/colorSurface" android:orientation="vertical"> @@ -40,7 +40,6 @@ android:layout_weight="1" android:orientation="horizontal"> - + + + + + + + + @@ -107,13 +134,51 @@ android:fontFamily="@font/poppins_semi_bold" android:text="@string/lorem_ipsum" android:textSize="12sp" /> + + + + + + android:visibility="visible"> - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/item_activity_reply.xml b/app/src/main/res/layout/item_activity_reply.xml index 69c992f602..11e165930a 100644 --- a/app/src/main/res/layout/item_activity_reply.xml +++ b/app/src/main/res/layout/item_activity_reply.xml @@ -27,7 +27,6 @@ android:id="@+id/activityUserAvatar" android:layout_width="42dp" android:layout_height="42dp" - android:layout_gravity="center" app:srcCompat="@drawable/ic_round_add_circle_24" tools:ignore="ContentDescription,ImageContrastCheck" tools:tint="@color/transparent" /> @@ -41,7 +40,6 @@ android:layout_weight="1" android:orientation="horizontal"> - @@ -107,4 +106,55 @@ android:fontFamily="@font/poppins_semi_bold" android:text="@string/lorem_ipsum" android:textSize="12sp" /> + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_comments.xml b/app/src/main/res/layout/item_comments.xml index e5e2d7861e..679b9a7608 100644 --- a/app/src/main/res/layout/item_comments.xml +++ b/app/src/main/res/layout/item_comments.xml @@ -224,7 +224,7 @@ android:alpha="0.6" android:fontFamily="@font/poppins_semi_bold" android:gravity="center" - android:text="Reply" + android:text="@string/reply" android:textSize="12sp" app:layout_constraintStart_toEndOf="@+id/commentDownVote" app:layout_constraintTop_toBottomOf="@+id/commentText" @@ -238,7 +238,7 @@ android:alpha="0.6" android:fontFamily="@font/poppins_semi_bold" android:gravity="center" - android:text="Edit" + android:text="@string/edit" android:textSize="12sp" app:layout_constraintBottom_toBottomOf="@+id/commentReply" app:layout_constraintStart_toEndOf="@+id/commentReply"