feat(profile page): added fav anime and manga
This commit is contained in:
parent
dbe837be28
commit
03b8e7dab6
6 changed files with 288 additions and 21 deletions
|
@ -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>(
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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")?: ""
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
Loading…
Add table
Add a link
Reference in a new issue