feat(profile page): added fav anime and manga

This commit is contained in:
aayush262 2024-03-03 16:24:36 +05:30
parent dbe837be28
commit 03b8e7dab6
6 changed files with 288 additions and 21 deletions

View file

@ -66,6 +66,32 @@ class AnilistQueries {
show = true show = true
) )
} }
suspend fun userFavMedia(anime: Boolean, id: Int): ArrayList<Media> {
var hasNextPage = true
var page = 0
suspend fun getNextPage(page: Int): List<Media> {
val response = executeQuery<Query.User>("""{${userFavMediaQuery(anime, page, id)}}""")
val favourites = response?.data?.user?.favourites
val apiMediaList = if (anime) favourites?.anime else favourites?.manga
hasNextPage = apiMediaList?.pageInfo?.hasNextPage ?: false
return apiMediaList?.edges?.mapNotNull {
it.node?.let { i ->
Media(i).apply { isFav = true }
}
} ?: return listOf()
}
val responseArray = arrayListOf<Media>()
while (hasNextPage) {
page++
responseArray.addAll(getNextPage(page))
}
return responseArray
}
private fun userFavMediaQuery(anime: Boolean, page: Int, id: Int): String {
return """User(id:${id}){id favourites{${if (anime) "anime" else "manga"}(page:$page){pageInfo{hasNextPage}edges{favouriteOrder node{id idMal isAdult mediaListEntry{ progress private score(format:POINT_100) status } chapters isFavourite format episodes nextAiringEpisode{episode}meanScore isFavourite format startDate{year month day} title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}}}"""
}
suspend fun getMedia(id: Int, mal: Boolean = false): Media? { suspend fun getMedia(id: Int, mal: Boolean = false): Media? {
val response = executeQuery<Query.Media>( val response = executeQuery<Query.Media>(

View file

@ -333,3 +333,19 @@ class GenresViewModel : ViewModel() {
} }
} }
} }
class ProfileViewModel : ViewModel(){
private val animeFav: MutableLiveData<ArrayList<Media>> =
MutableLiveData<ArrayList<Media>>(null)
fun getAnimeFav(): LiveData<ArrayList<Media>> = animeFav
suspend fun setAnimeFav(id: Int) {
animeFav.postValue(Anilist.query.userFavMedia(true, id))
}
private val mangaFav: MutableLiveData<ArrayList<Media>> =
MutableLiveData<ArrayList<Media>>(null)
fun getMangaFav(): LiveData<ArrayList<Media>> = mangaFav
suspend fun setMangaFav(id: Int) {
mangaFav.postValue(Anilist.query.userFavMedia(false, id))
}
}

View file

@ -53,7 +53,7 @@ class ProfileActivity : AppCompatActivity(){
navBar.addTab(profileTab) navBar.addTab(profileTab)
navBar.addTab(statsTab) navBar.addTab(statsTab)
navBar.visibility = View.GONE navBar.visibility = View.GONE
binding.mediaViewPager.isUserInputEnabled = false binding.profileViewPager.isUserInputEnabled = false
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
val userid = intent.getIntExtra("userId", 0) val userid = intent.getIntExtra("userId", 0)
val respond = Anilist.query.getUserProfile(userid) val respond = Anilist.query.getUserProfile(userid)
@ -64,7 +64,8 @@ class ProfileActivity : AppCompatActivity(){
return@launch return@launch
} }
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
binding.mediaViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, user, this@ProfileActivity) binding.profileViewPager.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = navBarHeight }
binding.profileViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, user, this@ProfileActivity)
navBar.visibility = View.VISIBLE navBar.visibility = View.VISIBLE
navBar.selectTabAt(selected) navBar.selectTabAt(selected)
navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener { navBar.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
@ -75,7 +76,7 @@ class ProfileActivity : AppCompatActivity(){
newTab: AnimatedBottomBar.Tab newTab: AnimatedBottomBar.Tab
) { ) {
selected = newIndex selected = newIndex
binding.mediaViewPager.setCurrentItem(selected, true) binding.profileViewPager.setCurrentItem(selected, true)
} }
}) })
val userLevel = intent.getStringExtra("username")?: "" val userLevel = intent.getStringExtra("username")?: ""

View file

@ -5,13 +5,27 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.LayoutAnimationController
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import ani.dantotsu.bottomBar
import ani.dantotsu.buildMarkwon import ani.dantotsu.buildMarkwon
import ani.dantotsu.connections.anilist.ProfileViewModel
import ani.dantotsu.connections.anilist.api.Query import ani.dantotsu.connections.anilist.api.Query
import ani.dantotsu.databinding.FragmentProfileBinding import ani.dantotsu.databinding.FragmentProfileBinding
import ani.dantotsu.loadImage import ani.dantotsu.loadImage
import ani.dantotsu.media.Media
import ani.dantotsu.media.MediaAdaptor
import ani.dantotsu.media.user.ListActivity import ani.dantotsu.media.user.ListActivity
import ani.dantotsu.setSlideIn
import ani.dantotsu.setSlideUp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class ProfileFragment(private val user: Query.UserProfile, private val activity: ProfileActivity): Fragment() { class ProfileFragment(private val user: Query.UserProfile, private val activity: ProfileActivity): Fragment() {
lateinit var binding: FragmentProfileBinding lateinit var binding: FragmentProfileBinding
@ -24,6 +38,7 @@ class ProfileFragment(private val user: Query.UserProfile, private val activity:
return binding.root return binding.root
} }
val model: ProfileViewModel by activityViewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val markwon = buildMarkwon(activity, false) val markwon = buildMarkwon(activity, false)
@ -58,5 +73,66 @@ class ProfileFragment(private val user: Query.UserProfile, private val activity:
binding.statsMangaMeanScore.text = user.statistics.manga.meanScore.toString() binding.statsMangaMeanScore.text = user.statistics.manga.meanScore.toString()
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
model.setAnimeFav(user.id)
model.setMangaFav(user.id)
} }
initRecyclerView(
model.getAnimeFav(),
binding.profileFavAnimeContainer,
binding.profileFavAnimeRecyclerView,
binding.profileFavAnimeProgressBar,
binding.profileFavAnimeEmpty,
binding.profileFavAnime
)
initRecyclerView(
model.getMangaFav(),
binding.profileFavMangaContainer,
binding.profileFavMangaRecyclerView,
binding.profileFavMangaProgressBar,
binding.profileFavMangaEmpty,
binding.profileFavManga
)
}
private fun initRecyclerView(
mode: LiveData<ArrayList<Media>>,
container: View,
recyclerView: RecyclerView,
progress: View,
empty: View,
title: View
) {
container.visibility = View.VISIBLE
progress.visibility = View.VISIBLE
recyclerView.visibility = View.GONE
empty.visibility = View.GONE
title.visibility = View.INVISIBLE
mode.observe(viewLifecycleOwner) {
recyclerView.visibility = View.GONE
empty.visibility = View.GONE
if (it != null) {
if (it.isNotEmpty()) {
recyclerView.adapter = MediaAdaptor(0, it, requireActivity())
recyclerView.layoutManager = LinearLayoutManager(
requireContext(),
LinearLayoutManager.HORIZONTAL,
false
)
recyclerView.visibility = View.VISIBLE
recyclerView.layoutAnimation =
LayoutAnimationController(setSlideIn(), 0.25f)
} else {
empty.visibility = View.VISIBLE
}
title.visibility = View.VISIBLE
title.startAnimation(setSlideUp())
progress.visibility = View.GONE
}
}
}
} }

View file

@ -22,6 +22,7 @@
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:scrollbars="none"
android:layout_marginBottom="72dp"> android:layout_marginBottom="72dp">
<LinearLayout <LinearLayout
@ -66,9 +67,10 @@
<com.google.android.material.imageview.ShapeableImageView <com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profileUserAvatar" android:id="@+id/profileUserAvatar"
android:layout_width="78dp" android:layout_width="82dp"
android:layout_height="78dp" android:layout_height="82dp"
android:layout_gravity="center" android:layout_gravity="center"
app:srcCompat="@drawable/ic_round_add_circle_24"
tools:tint="@color/transparent" tools:tint="@color/transparent"
tools:ignore="ContentDescription,ImageContrastCheck" /> tools:ignore="ContentDescription,ImageContrastCheck" />
@ -94,7 +96,7 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.viewpager2.widget.ViewPager2 <androidx.viewpager2.widget.ViewPager2
android:id="@+id/mediaViewPager" android:id="@+id/profileViewPager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:nestedScrollingEnabled="true" android:nestedScrollingEnabled="true"

View file

@ -139,10 +139,10 @@
android:id="@+id/profileUserStatsTitle" android:id="@+id/profileUserStatsTitle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="18dp" android:layout_marginStart="32dp"
android:layout_marginTop="24dp" android:layout_marginTop="8dp"
android:textColor="?attr/colorPrimary" android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_semi_bold" android:fontFamily="@font/poppins_bold"
android:text="Stats" android:text="Stats"
android:textSize="18sp" android:textSize="18sp"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
@ -337,10 +337,10 @@
android:id="@+id/profileUserBioTitle" android:id="@+id/profileUserBioTitle"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="18dp" android:layout_marginStart="32dp"
android:layout_marginTop="24dp" android:layout_marginTop="8dp"
android:textColor="?attr/colorPrimary" android:layout_marginEnd="32dp"
android:fontFamily="@font/poppins_semi_bold" android:fontFamily="@font/poppins_bold"
android:text="Bio" android:text="Bio"
android:textSize="18sp" android:textSize="18sp"
tools:ignore="HardcodedText" /> tools:ignore="HardcodedText" />
@ -349,13 +349,159 @@
android:id="@+id/profileUserBio" android:id="@+id/profileUserBio"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fontFamily="@font/poppins_semi_bold" android:layout_marginStart="16dp"
android:paddingStart="32dp" android:layout_marginEnd="16dp"
android:paddingTop="16dp" android:ellipsize="end"
android:paddingEnd="32dp" android:maxLines="5"
android:alpha="0.58" android:padding="16dp"
android:textSize="12sp" tools:text="@string/slogan"/>
tools:text="@tools:sample/lorem"/>
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/profileFavAnimeContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/profileFavAnime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:fontFamily="@font/poppins_bold"
android:padding="8dp"
android:text="@string/fav_anime"
android:textSize="16sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="250dp">
<LinearLayout
android:id="@+id/profileFavAnimeEmpty"
android:layout_width="match_parent"
android:layout_height="250dp"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="match_parent"
android:layout_height="32dp"
android:src="@drawable/ic_round_heart_broken_24"
app:tint="?attr/colorPrimary"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.58"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="User has no favorite anime"
android:textAlignment="center"
tools:ignore="TextContrastCheck" />
</LinearLayout>
<ProgressBar
android:id="@+id/profileFavAnimeProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="90dp" />
<ani.dantotsu.FadingEdgeRecyclerView
android:id="@+id/profileFavAnimeRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:requiresFadingEdge="horizontal"
tools:itemCount="4"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_media_compact"
tools:orientation="horizontal" />
</FrameLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/profileFavMangaContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="gone">
<TextView
android:id="@+id/profileFavManga"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:fontFamily="@font/poppins_bold"
android:padding="8dp"
android:text="@string/fav_manga"
android:textSize="16sp" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="250dp">
<LinearLayout
android:id="@+id/profileFavMangaEmpty"
android:layout_width="match_parent"
android:layout_height="250dp"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="match_parent"
android:layout_height="32dp"
android:src="@drawable/ic_round_heart_broken_24"
app:tint="?attr/colorPrimary"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.58"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:text="User has no favorite manga."
android:textAlignment="center"
tools:ignore="TextContrastCheck" />
</LinearLayout>
<ProgressBar
android:id="@+id/profileFavMangaProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="90dp" />
<ani.dantotsu.FadingEdgeRecyclerView
android:id="@+id/profileFavMangaRecyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:requiresFadingEdge="horizontal"
tools:itemCount="4"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_media_compact"
tools:orientation="horizontal" />
</FrameLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>