From e49f0dbf32fec4a85e42414a572bf447a43d9f7d Mon Sep 17 00:00:00 2001 From: aayush262 Date: Sun, 7 Apr 2024 00:51:50 +0530 Subject: [PATCH] feat: socials in media --- .github/workflows/beta.yml | 6 +-- .../connections/anilist/AnilistQueries.kt | 25 ++++++++-- .../dantotsu/connections/anilist/api/Data.kt | 4 +- app/src/main/java/ani/dantotsu/media/Media.kt | 3 +- .../ani/dantotsu/media/MediaInfoFragment.kt | 17 +++++++ .../ani/dantotsu/media/MediaSocialAdapter.kt | 49 +++++++++++++++++++ .../main/java/ani/dantotsu/profile/User.kt | 1 + .../main/res/layout/item_follower_grid.xml | 28 ++++++++--- app/src/main/res/values/strings.xml | 2 + 9 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/ani/dantotsu/media/MediaSocialAdapter.kt diff --git a/.github/workflows/beta.yml b/.github/workflows/beta.yml index 558343ab..9670e55c 100644 --- a/.github/workflows/beta.yml +++ b/.github/workflows/beta.yml @@ -117,9 +117,9 @@ jobs: #Telegram curl -X POST \ - -d chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }} \ - -d text="Alpha-Build: ${VERSION}: ${commit_messages}" \ - https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage + -d chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }} \ + -d text="Alpha-Build: ${VERSION}: ${commit_messages}" \ + https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage curl -F "chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }}" \ -F "document=@app/build/outputs/apk/google/alpha/app-google-armeabi-v7a-alpha.apk" \ https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendDocument 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 411317c8..401a5b3b 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/AnilistQueries.kt @@ -20,6 +20,7 @@ import ani.dantotsu.media.Character import ani.dantotsu.media.Media import ani.dantotsu.media.Studio import ani.dantotsu.others.MalScraper +import ani.dantotsu.profile.User import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.snackString @@ -72,14 +73,14 @@ class AnilistQueries { media.cameFromContinue = false val query = - """{Media(id:${media.id}){id favourites popularity mediaListEntry{id status score(format:POINT_100)progress private notes repeat customLists updatedAt startedAt{year month day}completedAt{year month day}}isFavourite siteUrl idMal nextAiringEpisode{episode airingAt}source countryOfOrigin format duration season seasonYear startDate{year month day}endDate{year month day}genres studios(isMain:true){nodes{id name siteUrl}}description trailer{site id}synonyms tags{name rank isMediaSpoiler}characters(sort:[ROLE,FAVOURITES_DESC],perPage:25,page:1){edges{role voiceActors { id name { first middle last full native userPreferred } image { large medium } languageV2 } node{id image{medium}name{userPreferred}isFavourite}}}relations{edges{relationType(version:2)node{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}popularity meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}staffPreview:staff(perPage:8,sort:[RELEVANCE,ID]){edges{role node{id image{large medium}name{userPreferred}}}}recommendations(sort:RATING_DESC){nodes{mediaRecommendation{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}externalLinks{url site}}}""" + """{Media(id:${media.id}){id favourites popularity mediaListEntry{id status score(format:POINT_100)progress private notes repeat customLists updatedAt startedAt{year month day}completedAt{year month day}}isFavourite siteUrl idMal nextAiringEpisode{episode airingAt}source countryOfOrigin format duration season seasonYear startDate{year month day}endDate{year month day}genres studios(isMain:true){nodes{id name siteUrl}}description trailer{site id}synonyms tags{name rank isMediaSpoiler}characters(sort:[ROLE,FAVOURITES_DESC],perPage:25,page:1){edges{role voiceActors { id name { first middle last full native userPreferred } image { large medium } languageV2 } node{id image{medium}name{userPreferred}isFavourite}}}relations{edges{relationType(version:2)node{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}popularity meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}staffPreview:staff(perPage:8,sort:[RELEVANCE,ID]){edges{role node{id image{large medium}name{userPreferred}}}}recommendations(sort:RATING_DESC){nodes{mediaRecommendation{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}externalLinks{url site}}Page(page:1){pageInfo{total perPage currentPage lastPage hasNextPage}mediaList(isFollowing:true,sort:[STARTED_ON],mediaId:${media.id}){id status score progress progressVolumes user{id name avatar{large medium}}}}}""" runBlocking { val anilist = async { var response = executeQuery(query, force = true, show = true) if (response != null) { fun parse() { val fetchedMedia = response?.data?.media ?: return - + val user = response?.data?.page media.source = fetchedMedia.source?.toString() media.countryOfOrigin = fetchedMedia.countryOfOrigin media.format = fetchedMedia.format?.toString() @@ -144,7 +145,7 @@ class AnilistQueries { Author( id = it.id, name = it.name?.userPreferred, - image = it.image?.medium, + image = it.image?.large, role = it.languageV2 ) } as ArrayList @@ -161,7 +162,7 @@ class AnilistQueries { Author( id = id, name = i.node?.name?.userPreferred, - image = i.node?.image?.medium, + image = i.node?.image?.large, role = when (i.role.toString()) { "MAIN" -> currContext()?.getString(R.string.main_role) ?: "MAIN" @@ -208,7 +209,21 @@ class AnilistQueries { } } } - + if (user?.mediaList?.isNotEmpty() == true) { + media.users = user.mediaList?.mapNotNull { + it.user?.let { user -> + if (user.id != Anilist.userid) { + User( + user.id, + user.name ?: "Unknown", + user.avatar?.large, + "", + it.status?.toString(), + ) + } else null + } + }?.toCollection(arrayListOf()) ?: arrayListOf() + } if (fetchedMedia.mediaListEntry != null) { fetchedMedia.mediaListEntry?.apply { media.userProgress = progress diff --git a/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt b/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt index 1a83b7cc..499d4c30 100644 --- a/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt +++ b/app/src/main/java/ani/dantotsu/connections/anilist/api/Data.kt @@ -24,7 +24,9 @@ class Query { @Serializable data class Data( @SerialName("Media") - val media: ani.dantotsu.connections.anilist.api.Media? + val media: ani.dantotsu.connections.anilist.api.Media?, + @SerialName("Page") + val page: ani.dantotsu.connections.anilist.api.Page? ) } diff --git a/app/src/main/java/ani/dantotsu/media/Media.kt b/app/src/main/java/ani/dantotsu/media/Media.kt index cd5a8f73..7f2150c9 100644 --- a/app/src/main/java/ani/dantotsu/media/Media.kt +++ b/app/src/main/java/ani/dantotsu/media/Media.kt @@ -7,6 +7,7 @@ import ani.dantotsu.connections.anilist.api.MediaList import ani.dantotsu.connections.anilist.api.MediaType import ani.dantotsu.media.anime.Anime import ani.dantotsu.media.manga.Manga +import ani.dantotsu.profile.User import java.io.Serializable import ani.dantotsu.connections.anilist.api.Media as ApiMedia @@ -66,7 +67,7 @@ data class Media( var sequel: Media? = null, var relations: ArrayList? = null, var recommendations: ArrayList? = null, - + var users: ArrayList? = null, var vrvId: String? = null, var crunchySlug: String? = null, diff --git a/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt b/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt index 609de856..c9f365be 100644 --- a/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt +++ b/app/src/main/java/ani/dantotsu/media/MediaInfoFragment.kt @@ -570,6 +570,23 @@ class MediaInfoFragment : Fragment() { parent.addView(root) } } + if(!media.users.isNullOrEmpty() && !offline){ + ItemTitleRecyclerBinding.inflate( + LayoutInflater.from(context), + parent, + false + ).apply { + itemTitle.setText(R.string.social) + itemRecycler.adapter = + MediaSocialAdapter(media.users!!) + itemRecycler.layoutManager = LinearLayoutManager( + requireContext(), + LinearLayoutManager.HORIZONTAL, + false + ) + parent.addView(root) + } + } } } diff --git a/app/src/main/java/ani/dantotsu/media/MediaSocialAdapter.kt b/app/src/main/java/ani/dantotsu/media/MediaSocialAdapter.kt new file mode 100644 index 00000000..8fd04e4b --- /dev/null +++ b/app/src/main/java/ani/dantotsu/media/MediaSocialAdapter.kt @@ -0,0 +1,49 @@ +package ani.dantotsu.media + +import android.app.Activity +import android.content.Context +import android.content.Intent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.core.content.ContextCompat +import androidx.recyclerview.widget.RecyclerView +import ani.dantotsu.databinding.ItemFollowerGridBinding +import ani.dantotsu.loadImage +import ani.dantotsu.profile.ProfileActivity +import ani.dantotsu.profile.User +import ani.dantotsu.setAnimation + +class MediaSocialAdapter(private val user: ArrayList) : + RecyclerView.Adapter() { + + inner class DeveloperViewHolder(val binding: ItemFollowerGridBinding) : + RecyclerView.ViewHolder(binding.root) + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DeveloperViewHolder { + return DeveloperViewHolder( + ItemFollowerGridBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + ) + } + + override fun onBindViewHolder(holder: DeveloperViewHolder, position: Int) { + val b = holder.binding + setAnimation(b.root.context, b.root) + val user = user[position] + b.profileUserName.text = user.name + b.profileUserAvatar.loadImage(user.pfp) + b.profileInfo.text = user.info + b.profileInfo.visibility = View.VISIBLE + b.profileUserAvatar.setOnClickListener { + val intent = Intent(b.root.context, ProfileActivity::class.java) + intent.putExtra("userId", user.id) + ContextCompat.startActivity(b.root.context, intent, null) + } + } + + override fun getItemCount(): Int = user.size +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/profile/User.kt b/app/src/main/java/ani/dantotsu/profile/User.kt index 53c41737..daa53b0f 100644 --- a/app/src/main/java/ani/dantotsu/profile/User.kt +++ b/app/src/main/java/ani/dantotsu/profile/User.kt @@ -5,4 +5,5 @@ data class User( val name: String, val pfp: String?, val banner: String?, + val info: String? = null, ) \ No newline at end of file diff --git a/app/src/main/res/layout/item_follower_grid.xml b/app/src/main/res/layout/item_follower_grid.xml index 56132bbe..9d4bdad7 100644 --- a/app/src/main/res/layout/item_follower_grid.xml +++ b/app/src/main/res/layout/item_follower_grid.xml @@ -4,8 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="8dp" - android:orientation="vertical"> + android:orientation="vertical" + android:padding="8dp"> + + + tools:ignore="ContentDescription,ImageContrastCheck" + tools:tint="@color/transparent" /> + android:textStyle="bold" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ddceedf..24d19bea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -888,4 +888,6 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc Voice Actors Permission is required to download Media + Users + Social