feat: statistics (wip)
This commit is contained in:
parent
533148069f
commit
500de4e45e
12 changed files with 690 additions and 356 deletions
|
@ -6,58 +6,123 @@ import android.os.Bundle
|
|||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.api.Query
|
||||
import ani.dantotsu.databinding.ActivityProfileBinding
|
||||
import ani.dantotsu.initActivity
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaDetailsActivity
|
||||
import ani.dantotsu.media.user.ListActivity
|
||||
import ani.dantotsu.others.ImageViewDialog
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.themes.ThemeManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||
|
||||
|
||||
class ProfileActivity : AppCompatActivity(){
|
||||
private lateinit var binding: ActivityProfileBinding
|
||||
private var selected: Int = 0
|
||||
private lateinit var tabLayout: AnimatedBottomBar
|
||||
@SuppressLint("SetTextI18n")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
ThemeManager(this).applyTheme()
|
||||
initActivity(this)
|
||||
binding = ActivityProfileBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
tabLayout = binding.typeTab
|
||||
val profileTab = tabLayout.createTab(R.drawable.ic_round_person_24, "Profile")
|
||||
val statsTab = tabLayout.createTab(R.drawable.ic_stats_24, "Stats")
|
||||
tabLayout.addTab(profileTab)
|
||||
tabLayout.addTab(statsTab)
|
||||
tabLayout.visibility = View.GONE
|
||||
binding.mediaViewPager.isUserInputEnabled = false
|
||||
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val userid = intent.getIntExtra("userId", 0)
|
||||
val respond = Anilist.query.getUserProfile(userid)
|
||||
val user = respond?.data?.user ?: return@launch
|
||||
val userLevel = intent.getStringExtra("username")
|
||||
val user = respond?.data?.user
|
||||
if (user == null) {
|
||||
snackString("User not found")
|
||||
finish()
|
||||
return@launch
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.mediaViewPager.adapter = ViewPagerAdapter(supportFragmentManager, lifecycle, user, this@ProfileActivity)
|
||||
tabLayout.visibility = View.VISIBLE
|
||||
tabLayout.selectTabAt(selected)
|
||||
tabLayout.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
|
||||
override fun onTabSelected(
|
||||
lastIndex: Int,
|
||||
lastTab: AnimatedBottomBar.Tab?,
|
||||
newIndex: Int,
|
||||
newTab: AnimatedBottomBar.Tab
|
||||
) {
|
||||
selected = newIndex
|
||||
binding.mediaViewPager.setCurrentItem(selected, true)
|
||||
}
|
||||
})
|
||||
val userLevel = intent.getStringExtra("username")?: ""
|
||||
|
||||
binding.profileProgressBar.visibility = View.GONE
|
||||
binding.profileBannerImage.loadImage(user.bannerImage)
|
||||
binding.profileUserAvatar.loadImage(user.avatar?.medium)
|
||||
binding.profileUserName.text = "${user.name} $userLevel"
|
||||
binding.profileUserInfo.text = user.about
|
||||
binding.profileAnimeList.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
this@ProfileActivity, Intent(this@ProfileActivity, ListActivity::class.java)
|
||||
.putExtra("anime", true)
|
||||
.putExtra("userId", user.id)
|
||||
.putExtra("username", user.name), null
|
||||
)
|
||||
}
|
||||
binding.profileMangaList.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
this@ProfileActivity, Intent(this@ProfileActivity, ListActivity::class.java)
|
||||
.putExtra("anime", false)
|
||||
.putExtra("userId", user.id)
|
||||
.putExtra("username", user.name), null
|
||||
)
|
||||
}
|
||||
binding.profileUserEpisodesWatched.text = user.statistics.anime.episodesWatched.toString()
|
||||
binding.profileUserChaptersRead.text = user.statistics.manga.chaptersRead.toString()
|
||||
|
||||
binding.profileAnimeListImage.loadImage("https://bit.ly/31bsIHq")
|
||||
binding.profileMangaListImage.loadImage("https://bit.ly/2ZGfcuG")
|
||||
binding.profileBannerImage.loadImage(user.bannerImage)
|
||||
binding.profileBannerImage.setOnLongClickListener {
|
||||
ImageViewDialog.newInstance(
|
||||
this@ProfileActivity,
|
||||
user.name + " [Banner]",
|
||||
user.bannerImage
|
||||
)
|
||||
}
|
||||
binding.profileUserAvatar.loadImage(user.avatar?.medium)
|
||||
binding.profileUserAvatar.setOnLongClickListener {
|
||||
ImageViewDialog.newInstance(
|
||||
this@ProfileActivity,
|
||||
user.name + " [Avatar]",
|
||||
user.avatar?.medium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (this::tabLayout.isInitialized) {
|
||||
tabLayout.selectTabAt(selected)
|
||||
}
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
private class ViewPagerAdapter(
|
||||
fragmentManager: FragmentManager,
|
||||
lifecycle: Lifecycle,
|
||||
private val user: Query.UserProfile,
|
||||
private val activity: ProfileActivity
|
||||
) :
|
||||
FragmentStateAdapter(fragmentManager, lifecycle) {
|
||||
|
||||
override fun getItemCount(): Int = 2
|
||||
override fun createFragment(position: Int): Fragment = when (position) {
|
||||
0 -> ProfileFragment(user, activity)
|
||||
1 -> StatsFragment(user, activity)
|
||||
else -> ProfileFragment(user, activity)
|
||||
}
|
||||
}
|
||||
}
|
50
app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
Normal file
50
app/src/main/java/ani/dantotsu/profile/ProfileFragment.kt
Normal file
|
@ -0,0 +1,50 @@
|
|||
package ani.dantotsu.profile
|
||||
|
||||
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.fragment.app.Fragment
|
||||
import ani.dantotsu.buildMarkwon
|
||||
import ani.dantotsu.connections.anilist.api.Query
|
||||
import ani.dantotsu.databinding.FragmentProfileBinding
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.media.user.ListActivity
|
||||
|
||||
class ProfileFragment(private val user: Query.UserProfile, private val activity: ProfileActivity): Fragment() {
|
||||
lateinit var binding: FragmentProfileBinding
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = FragmentProfileBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val markwon = buildMarkwon(activity, false)
|
||||
markwon.setMarkdown(binding.profileUserInfo, user.about?:"")
|
||||
binding.profileAnimeList.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
activity, Intent(activity, ListActivity::class.java)
|
||||
.putExtra("anime", true)
|
||||
.putExtra("userId", user.id)
|
||||
.putExtra("username", user.name), null
|
||||
)
|
||||
}
|
||||
binding.profileMangaList.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
activity, Intent(activity, ListActivity::class.java)
|
||||
.putExtra("anime", false)
|
||||
.putExtra("userId", user.id)
|
||||
.putExtra("username", user.name), null
|
||||
)
|
||||
}
|
||||
binding.profileAnimeListImage.loadImage("https://bit.ly/31bsIHq")
|
||||
binding.profileMangaListImage.loadImage("https://bit.ly/2ZGfcuG")
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
package ani.dantotsu.profile
|
||||
|
||||
class StatisticsActivity {
|
||||
}
|
157
app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
Normal file
157
app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
Normal file
|
@ -0,0 +1,157 @@
|
|||
package ani.dantotsu.profile
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.api.Query
|
||||
import ani.dantotsu.databinding.FragmentStatisticsBinding
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartAlignType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartLayoutType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartModel
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartStackingType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartVerticalAlignType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartZoomType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AADataElement
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAOptions
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AASeriesElement
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.aa_toAAOptions
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAChart
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AALang
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAPosition
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAScrollablePlotArea
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAStyle
|
||||
import com.github.aachartmodel.aainfographics.aatools.AAColor
|
||||
import com.github.aachartmodel.aainfographics.aatools.AAGradientColor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import nl.joery.animatedbottombar.AnimatedBottomBar
|
||||
|
||||
class StatsFragment(private val user: Query.UserProfile, private val activity: ProfileActivity) :
|
||||
Fragment() {
|
||||
private lateinit var binding: FragmentStatisticsBinding
|
||||
private var selected: Int = 0
|
||||
private lateinit var tabLayout: AnimatedBottomBar
|
||||
private var stats: Query.StatisticsResponse? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = FragmentStatisticsBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
tabLayout = binding.typeTab
|
||||
val animeTab = tabLayout.createTab(R.drawable.ic_round_movie_filter_24, "Anime")
|
||||
val mangaTab = tabLayout.createTab(R.drawable.ic_round_menu_book_24, "Manga")
|
||||
tabLayout.addTab(animeTab)
|
||||
tabLayout.addTab(mangaTab)
|
||||
|
||||
tabLayout.visibility = View.GONE
|
||||
activity.lifecycleScope.launch {
|
||||
stats = Anilist.query.getUserStatistics(user.id)
|
||||
withContext(Dispatchers.Main) {
|
||||
tabLayout.visibility = View.VISIBLE
|
||||
tabLayout.setOnTabSelectListener(object : AnimatedBottomBar.OnTabSelectListener {
|
||||
override fun onTabSelected(
|
||||
lastIndex: Int,
|
||||
lastTab: AnimatedBottomBar.Tab?,
|
||||
newIndex: Int,
|
||||
newTab: AnimatedBottomBar.Tab
|
||||
) {
|
||||
selected = newIndex
|
||||
when (newIndex) {
|
||||
0 -> loadAnimeStats()
|
||||
1 -> loadMangaStats()
|
||||
}
|
||||
}
|
||||
})
|
||||
tabLayout.selectTabAt(selected)
|
||||
loadAnimeStats()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (this::tabLayout.isInitialized) {
|
||||
tabLayout.selectTabAt(selected)
|
||||
}
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
private fun loadAnimeStats() {
|
||||
val formatChartModel = getFormatChartModel(true)
|
||||
if (formatChartModel != null) {
|
||||
val aaOptions = buildOptions(formatChartModel)
|
||||
binding.formatChartView.aa_drawChartWithChartOptions(aaOptions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadMangaStats() {
|
||||
val formatChartModel = getFormatChartModel(false)
|
||||
if (formatChartModel != null) {
|
||||
val aaOptions = buildOptions(formatChartModel)
|
||||
binding.formatChartView.aa_drawChartWithChartOptions(aaOptions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildOptions(aaChartModel: AAChartModel): AAOptions {
|
||||
val aaOptions = aaChartModel.aa_toAAOptions()
|
||||
aaOptions.tooltip?.apply {
|
||||
backgroundColor(AAGradientColor.PurpleLake)
|
||||
.style(AAStyle.style(AAColor.White))
|
||||
}
|
||||
aaOptions.chart?.zoomType = "xy"
|
||||
aaOptions.chart?.pinchType = "xy"
|
||||
aaOptions.legend?.apply {
|
||||
enabled(true)
|
||||
.verticalAlign(AAChartVerticalAlignType.Top)
|
||||
.layout(AAChartLayoutType.Vertical)
|
||||
.align(AAChartAlignType.Right)
|
||||
.itemMarginTop(10f)
|
||||
.labelFormat = "{name}: {y}"
|
||||
}
|
||||
aaOptions.plotOptions?.series?.connectNulls(true)
|
||||
return aaOptions
|
||||
}
|
||||
|
||||
private fun getFormatChartModel(anime: Boolean): AAChartModel? {
|
||||
val fotmatTypes: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.formats?.map { it.format } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.formats?.map { it.format } ?: emptyList()
|
||||
}
|
||||
val formatCount: List<Int> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.formats?.map { it.count } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.formats?.map { it.count } ?: emptyList()
|
||||
}
|
||||
if (fotmatTypes.isEmpty() || formatCount.isEmpty())
|
||||
return null
|
||||
return AAChartModel()
|
||||
.chartType(AAChartType.Pie)
|
||||
.title("Format")
|
||||
.zoomType(AAChartZoomType.XY)
|
||||
.dataLabelsEnabled(true)
|
||||
.series(getElements(fotmatTypes, formatCount))
|
||||
}
|
||||
|
||||
private fun getElements(types: List<String>, counts: List<Int>): Array<Any> {
|
||||
val elements = AASeriesElement()
|
||||
val dataElements = mutableListOf<AADataElement>()
|
||||
for (i in types.indices) {
|
||||
dataElements.add(AADataElement().name(types[i]).y(counts[i]))
|
||||
}
|
||||
return arrayOf(elements.data(dataElements.toTypedArray()))
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue