Initial commit
This commit is contained in:
commit
21bfbfb139
520 changed files with 47819 additions and 0 deletions
280
app/src/main/java/ani/dantotsu/home/AnimeFragment.kt
Normal file
280
app/src/main/java/ani/dantotsu/home/AnimeFragment.kt
Normal file
|
@ -0,0 +1,280 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.core.view.updatePaddingRelative
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.bottomBar
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistAnimeViewModel
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.connections.anilist.getUserId
|
||||
import ani.dantotsu.databinding.FragmentAnimeBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
import ani.dantotsu.media.ProgressAdapter
|
||||
import ani.dantotsu.media.SearchActivity
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.px
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class AnimeFragment : Fragment() {
|
||||
private var _binding: FragmentAnimeBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var uiSettings: UserInterfaceSettings = loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
val model: AnilistAnimeViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentAnimeBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView();_binding = null
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val scope = viewLifecycleOwner.lifecycleScope
|
||||
|
||||
var height = statusBarHeight
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val displayCutout = activity?.window?.decorView?.rootWindowInsets?.displayCutout
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
height = max(
|
||||
statusBarHeight,
|
||||
min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.animeRefresh.setSlingshotDistance(height + 128)
|
||||
binding.animeRefresh.setProgressViewEndTarget(false, height + 128)
|
||||
binding.animeRefresh.setOnRefreshListener {
|
||||
Refresh.activity[this.hashCode()]!!.postValue(true)
|
||||
}
|
||||
|
||||
binding.animePageRecyclerView.updatePaddingRelative(bottom = navBarHeight + 160f.px)
|
||||
|
||||
val animePageAdapter = AnimePageAdapter()
|
||||
|
||||
var loading = true
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.searchResults = SearchResults(
|
||||
"ANIME",
|
||||
isAdult = false,
|
||||
onList = false,
|
||||
results = mutableListOf(),
|
||||
hasNextPage = true,
|
||||
sort = Anilist.sortBy[1]
|
||||
)
|
||||
}
|
||||
val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity())
|
||||
val progressAdaptor = ProgressAdapter(searched = model.searched)
|
||||
val adapter = ConcatAdapter(animePageAdapter, popularAdaptor, progressAdaptor)
|
||||
binding.animePageRecyclerView.adapter = adapter
|
||||
val layout = LinearLayoutManager(requireContext())
|
||||
binding.animePageRecyclerView.layoutManager = layout
|
||||
|
||||
var visible = false
|
||||
fun animate() {
|
||||
val start = if (visible) 0f else 1f
|
||||
val end = if (!visible) 0f else 1f
|
||||
ObjectAnimator.ofFloat(binding.animePageScrollTop, "scaleX", start, end).apply {
|
||||
duration = 300
|
||||
interpolator = OvershootInterpolator(2f)
|
||||
start()
|
||||
}
|
||||
ObjectAnimator.ofFloat(binding.animePageScrollTop, "scaleY", start, end).apply {
|
||||
duration = 300
|
||||
interpolator = OvershootInterpolator(2f)
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
binding.animePageScrollTop.setOnClickListener {
|
||||
binding.animePageRecyclerView.scrollToPosition(4)
|
||||
binding.animePageRecyclerView.smoothScrollToPosition(0)
|
||||
}
|
||||
|
||||
var oldIncludeList = true
|
||||
|
||||
animePageAdapter.onIncludeListClick = { checked ->
|
||||
oldIncludeList = !checked
|
||||
loading = true
|
||||
model.searchResults.results.clear()
|
||||
popularAdaptor.notifyDataSetChanged()
|
||||
scope.launch(Dispatchers.IO) {
|
||||
model.loadPopular("ANIME", sort = Anilist.sortBy[1], onList = checked)
|
||||
}
|
||||
}
|
||||
|
||||
model.getPopular().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
if (oldIncludeList == (it.onList != false)) {
|
||||
val prev = model.searchResults.results.size
|
||||
model.searchResults.results.addAll(it.results)
|
||||
popularAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
} else {
|
||||
model.searchResults.results.addAll(it.results)
|
||||
popularAdaptor.notifyDataSetChanged()
|
||||
oldIncludeList = it.onList ?: true
|
||||
}
|
||||
model.searchResults.onList = it.onList
|
||||
model.searchResults.hasNextPage = it.hasNextPage
|
||||
model.searchResults.page = it.page
|
||||
if (it.hasNextPage)
|
||||
progressAdaptor.bar?.visibility = View.VISIBLE
|
||||
else {
|
||||
snackString(getString(R.string.jobless_message))
|
||||
progressAdaptor.bar?.visibility = View.GONE
|
||||
}
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
binding.animePageRecyclerView.addOnScrollListener(object :
|
||||
RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
|
||||
if (!v.canScrollVertically(1)) {
|
||||
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
loading = true
|
||||
model.loadNextPage(model.searchResults)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layout.findFirstVisibleItemPosition() > 1 && !visible) {
|
||||
binding.animePageScrollTop.visibility = View.VISIBLE
|
||||
visible = true
|
||||
animate()
|
||||
}
|
||||
|
||||
if (!v.canScrollVertically(-1)) {
|
||||
visible = false
|
||||
animate()
|
||||
scope.launch {
|
||||
delay(300)
|
||||
binding.animePageScrollTop.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
super.onScrolled(v, dx, dy)
|
||||
}
|
||||
})
|
||||
animePageAdapter.ready.observe(viewLifecycleOwner) { i ->
|
||||
if (i) {
|
||||
model.getUpdated().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
animePageAdapter.updateRecent(MediaAdaptor(0, it, requireActivity()))
|
||||
}
|
||||
}
|
||||
if (animePageAdapter.trendingViewPager != null) {
|
||||
animePageAdapter.updateHeight()
|
||||
model.getTrending().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
animePageAdapter.updateTrending(
|
||||
MediaAdaptor(
|
||||
if (uiSettings.smallView) 3 else 2,
|
||||
it,
|
||||
requireActivity(),
|
||||
viewPager = animePageAdapter.trendingViewPager
|
||||
)
|
||||
)
|
||||
animePageAdapter.updateAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.animePageScrollTop.translationY = -(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun load() = scope.launch(Dispatchers.Main) {
|
||||
animePageAdapter.updateAvatar()
|
||||
}
|
||||
|
||||
animePageAdapter.onSeasonClick = { i ->
|
||||
scope.launch(Dispatchers.IO) {
|
||||
model.loadTrending(i)
|
||||
}
|
||||
}
|
||||
|
||||
animePageAdapter.onSeasonLongClick = { i ->
|
||||
val (season, year) = Anilist.currentSeasons[i]
|
||||
ContextCompat.startActivity(
|
||||
requireContext(),
|
||||
Intent(requireContext(), SearchActivity::class.java)
|
||||
.putExtra("type", "ANIME")
|
||||
.putExtra("season", season)
|
||||
.putExtra("seasonYear", year.toString())
|
||||
.putExtra("search", true),
|
||||
null
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
val live = Refresh.activity.getOrPut(this.hashCode()) { MutableLiveData(false) }
|
||||
live.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
getUserId(requireContext()) {
|
||||
load()
|
||||
}
|
||||
model.loaded = true
|
||||
model.loadTrending(1)
|
||||
model.loadUpdated()
|
||||
model.loadPopular("ANIME", sort = Anilist.sortBy[1])
|
||||
}
|
||||
live.postValue(false)
|
||||
_binding?.animeRefresh?.isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (!model.loaded) Refresh.activity[this.hashCode()]!!.postValue(true)
|
||||
super.onResume()
|
||||
}
|
||||
}
|
170
app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
Normal file
170
app/src/main/java/ani/dantotsu/home/AnimePageAdapter.kt
Normal file
|
@ -0,0 +1,170 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LayoutAnimationController
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import ani.dantotsu.media.GenreActivity
|
||||
import ani.dantotsu.MediaPageTransformer
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.ItemAnimePageBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.media.CalendarActivity
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
import ani.dantotsu.media.SearchActivity
|
||||
import ani.dantotsu.px
|
||||
import ani.dantotsu.setSafeOnClickListener
|
||||
import ani.dantotsu.setSlideIn
|
||||
import ani.dantotsu.setSlideUp
|
||||
import ani.dantotsu.settings.SettingsDialogFragment
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.statusBarHeight
|
||||
|
||||
class AnimePageAdapter : RecyclerView.Adapter<AnimePageAdapter.AnimePageViewHolder>() {
|
||||
val ready = MutableLiveData(false)
|
||||
lateinit var binding: ItemAnimePageBinding
|
||||
private var trendHandler: Handler? = null
|
||||
private lateinit var trendRun: Runnable
|
||||
var trendingViewPager: ViewPager2? = null
|
||||
private var uiSettings: UserInterfaceSettings = loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnimePageViewHolder {
|
||||
val binding = ItemAnimePageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return AnimePageViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AnimePageViewHolder, position: Int) {
|
||||
binding = holder.binding
|
||||
trendingViewPager = binding.animeTrendingViewPager
|
||||
|
||||
binding.animeTitleContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
if (uiSettings.smallView) binding.animeTrendingContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = (-108f).px
|
||||
}
|
||||
|
||||
updateAvatar()
|
||||
|
||||
binding.animeSearchBar.hint = "ANIME"
|
||||
binding.animeSearchBarText.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
it.context,
|
||||
Intent(it.context, SearchActivity::class.java).putExtra("type", "ANIME"),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
binding.animeSearchBar.setEndIconOnClickListener {
|
||||
binding.animeSearchBarText.performClick()
|
||||
}
|
||||
|
||||
binding.animeUserAvatar.setSafeOnClickListener {
|
||||
SettingsDialogFragment().show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
|
||||
}
|
||||
|
||||
listOf(
|
||||
binding.animePreviousSeason,
|
||||
binding.animeThisSeason,
|
||||
binding.animeNextSeason
|
||||
).forEachIndexed { i, it ->
|
||||
it.setSafeOnClickListener { onSeasonClick.invoke(i) }
|
||||
it.setOnLongClickListener { onSeasonLongClick.invoke(i) }
|
||||
}
|
||||
|
||||
binding.animeGenreImage.loadImage("https://s4.anilist.co/file/anilistcdn/media/anime/banner/16498-8jpFCOcDmneX.jpg")
|
||||
binding.animeCalendarImage.loadImage("https://s4.anilist.co/file/anilistcdn/media/anime/banner/125367-hGPJLSNfprO3.jpg")
|
||||
|
||||
binding.animeGenre.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
it.context,
|
||||
Intent(it.context, GenreActivity::class.java).putExtra("type", "ANIME"),
|
||||
null
|
||||
)
|
||||
}
|
||||
binding.animeCalendar.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
it.context,
|
||||
Intent(it.context, CalendarActivity::class.java),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
binding.animeIncludeList.visibility = if(Anilist.userid!=null) View.VISIBLE else View.GONE
|
||||
binding.animeIncludeList.setOnCheckedChangeListener { _, isChecked ->
|
||||
onIncludeListClick.invoke(isChecked)
|
||||
}
|
||||
if (ready.value == false)
|
||||
ready.postValue(true)
|
||||
}
|
||||
|
||||
lateinit var onSeasonClick : ((Int)->Unit)
|
||||
lateinit var onSeasonLongClick : ((Int)->Boolean)
|
||||
lateinit var onIncludeListClick : ((Boolean)->Unit)
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
fun updateHeight() {
|
||||
trendingViewPager!!.updateLayoutParams { height += statusBarHeight }
|
||||
}
|
||||
|
||||
fun updateTrending(adaptor: MediaAdaptor) {
|
||||
binding.animeTrendingProgressBar.visibility = View.GONE
|
||||
binding.animeTrendingViewPager.adapter = adaptor
|
||||
binding.animeTrendingViewPager.offscreenPageLimit = 3
|
||||
binding.animeTrendingViewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER
|
||||
binding.animeTrendingViewPager.setPageTransformer(MediaPageTransformer())
|
||||
|
||||
trendHandler = Handler(Looper.getMainLooper())
|
||||
trendRun = Runnable {
|
||||
binding.animeTrendingViewPager.currentItem = binding.animeTrendingViewPager.currentItem + 1
|
||||
}
|
||||
binding.animeTrendingViewPager.registerOnPageChangeCallback(
|
||||
object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
trendHandler!!.removeCallbacks(trendRun)
|
||||
trendHandler!!.postDelayed(trendRun, 4000)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
binding.animeTrendingViewPager.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
binding.animeTitleContainer.startAnimation(setSlideUp(uiSettings))
|
||||
binding.animeListContainer.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
binding.animeSeasonsCont.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
}
|
||||
|
||||
fun updateRecent(adaptor: MediaAdaptor) {
|
||||
binding.animeUpdatedProgressBar.visibility = View.GONE
|
||||
binding.animeUpdatedRecyclerView.adapter = adaptor
|
||||
binding.animeUpdatedRecyclerView.layoutManager =
|
||||
LinearLayoutManager(binding.animeUpdatedRecyclerView.context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.animeUpdatedRecyclerView.visibility = View.VISIBLE
|
||||
|
||||
binding.animeRecently.visibility = View.VISIBLE
|
||||
binding.animeRecently.startAnimation(setSlideUp(uiSettings))
|
||||
binding.animeUpdatedRecyclerView.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
binding.animePopular.visibility = View.VISIBLE
|
||||
binding.animePopular.startAnimation(setSlideUp(uiSettings))
|
||||
}
|
||||
|
||||
fun updateAvatar() {
|
||||
if (Anilist.avatar != null && ready.value == true) {
|
||||
binding.animeUserAvatar.loadImage(Anilist.avatar)
|
||||
}
|
||||
}
|
||||
|
||||
inner class AnimePageViewHolder(val binding: ItemAnimePageBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
346
app/src/main/java/ani/dantotsu/home/HomeFragment.kt
Normal file
346
app/src/main/java/ani/dantotsu/home/HomeFragment.kt
Normal file
|
@ -0,0 +1,346 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LayoutAnimationController
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.bottomBar
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistHomeViewModel
|
||||
import ani.dantotsu.connections.anilist.getUserId
|
||||
import ani.dantotsu.currContext
|
||||
import ani.dantotsu.databinding.FragmentHomeBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.media.Media
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
import ani.dantotsu.settings.SettingsDialogFragment
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.media.user.ListActivity
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.setSafeOnClickListener
|
||||
import ani.dantotsu.setSlideIn
|
||||
import ani.dantotsu.setSlideUp
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
|
||||
class HomeFragment : Fragment() {
|
||||
private var _binding: FragmentHomeBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FragmentHomeBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
val model: AnilistHomeViewModel by activityViewModels()
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val scope = lifecycleScope
|
||||
var uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
fun load() {
|
||||
if (activity != null && _binding != null) lifecycleScope.launch(Dispatchers.Main) {
|
||||
binding.homeUserName.text = Anilist.username
|
||||
binding.homeUserEpisodesWatched.text = Anilist.episodesWatched.toString()
|
||||
binding.homeUserChaptersRead.text = Anilist.chapterRead.toString()
|
||||
binding.homeUserAvatar.loadImage(Anilist.avatar)
|
||||
if (!uiSettings.bannerAnimations) binding.homeUserBg.pause()
|
||||
binding.homeUserBg.loadImage(Anilist.bg)
|
||||
binding.homeUserDataProgressBar.visibility = View.GONE
|
||||
|
||||
binding.homeAnimeList.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireActivity(), Intent(requireActivity(), ListActivity::class.java)
|
||||
.putExtra("anime", true)
|
||||
.putExtra("userId", Anilist.userid)
|
||||
.putExtra("username", Anilist.username), null
|
||||
)
|
||||
}
|
||||
binding.homeMangaList.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
requireActivity(), Intent(requireActivity(), ListActivity::class.java)
|
||||
.putExtra("anime", false)
|
||||
.putExtra("userId", Anilist.userid)
|
||||
.putExtra("username", Anilist.username), null
|
||||
)
|
||||
}
|
||||
|
||||
binding.homeUserAvatarContainer.startAnimation(setSlideUp(uiSettings))
|
||||
binding.homeUserDataContainer.visibility = View.VISIBLE
|
||||
binding.homeUserDataContainer.layoutAnimation = LayoutAnimationController(setSlideUp(uiSettings), 0.25f)
|
||||
binding.homeAnimeList.visibility = View.VISIBLE
|
||||
binding.homeMangaList.visibility = View.VISIBLE
|
||||
binding.homeListContainer.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
}
|
||||
else {
|
||||
snackString(currContext()?.getString(R.string.please_reload))
|
||||
}
|
||||
}
|
||||
|
||||
binding.homeUserAvatarContainer.setSafeOnClickListener {
|
||||
SettingsDialogFragment().show(parentFragmentManager, "dialog")
|
||||
}
|
||||
|
||||
binding.homeContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = navBarHeight
|
||||
}
|
||||
binding.homeUserBg.updateLayoutParams { height += statusBarHeight }
|
||||
binding.homeTopContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
var reached = false
|
||||
val duration = (uiSettings.animationSpeed * 200).toLong()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
binding.homeScroll.setOnScrollChangeListener { _, _, _, _, _ ->
|
||||
if (!binding.homeScroll.canScrollVertically(1)) {
|
||||
reached = true
|
||||
bottomBar.animate().translationZ(0f).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(bottomBar, "elevation", 4f, 0f).setDuration(duration).start()
|
||||
} else {
|
||||
if (reached) {
|
||||
bottomBar.animate().translationZ(12f).setDuration(duration).start()
|
||||
ObjectAnimator.ofFloat(bottomBar, "elevation", 0f, 4f).setDuration(duration).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var height = statusBarHeight
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val displayCutout = activity?.window?.decorView?.rootWindowInsets?.displayCutout
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
height =
|
||||
max(statusBarHeight, min(displayCutout.boundingRects[0].width(), displayCutout.boundingRects[0].height()))
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.homeRefresh.setSlingshotDistance(height + 128)
|
||||
binding.homeRefresh.setProgressViewEndTarget(false, height + 128)
|
||||
binding.homeRefresh.setOnRefreshListener {
|
||||
Refresh.activity[1]!!.postValue(true)
|
||||
}
|
||||
|
||||
//UserData
|
||||
binding.homeUserDataProgressBar.visibility = View.VISIBLE
|
||||
binding.homeUserDataContainer.visibility = View.GONE
|
||||
if (model.loaded) {
|
||||
load()
|
||||
}
|
||||
//List Images
|
||||
model.getListImages().observe(viewLifecycleOwner) {
|
||||
if (it.isNotEmpty()) {
|
||||
binding.homeAnimeListImage.loadImage(it[0] ?: "https://bit.ly/31bsIHq")
|
||||
binding.homeMangaListImage.loadImage(it[1] ?: "https://bit.ly/2ZGfcuG")
|
||||
}
|
||||
}
|
||||
|
||||
//Function For Recycler Views
|
||||
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(uiSettings), 0.25f)
|
||||
|
||||
} else {
|
||||
empty.visibility = View.VISIBLE
|
||||
}
|
||||
title.visibility = View.VISIBLE
|
||||
title.startAnimation(setSlideUp(uiSettings))
|
||||
progress.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Recycler Views
|
||||
initRecyclerView(
|
||||
model.getAnimeContinue(),
|
||||
binding.homeContinueWatchingContainer,
|
||||
binding.homeWatchingRecyclerView,
|
||||
binding.homeWatchingProgressBar,
|
||||
binding.homeWatchingEmpty,
|
||||
binding.homeContinueWatch
|
||||
)
|
||||
binding.homeWatchingBrowseButton.setOnClickListener {
|
||||
bottomBar.selectTabAt(0)
|
||||
}
|
||||
|
||||
initRecyclerView(
|
||||
model.getAnimeFav(),
|
||||
binding.homeFavAnimeContainer,
|
||||
binding.homeFavAnimeRecyclerView,
|
||||
binding.homeFavAnimeProgressBar,
|
||||
binding.homeFavAnimeEmpty,
|
||||
binding.homeFavAnime
|
||||
)
|
||||
|
||||
initRecyclerView(
|
||||
model.getAnimePlanned(),
|
||||
binding.homePlannedAnimeContainer,
|
||||
binding.homePlannedAnimeRecyclerView,
|
||||
binding.homePlannedAnimeProgressBar,
|
||||
binding.homePlannedAnimeEmpty,
|
||||
binding.homePlannedAnime
|
||||
)
|
||||
binding.homePlannedAnimeBrowseButton.setOnClickListener {
|
||||
bottomBar.selectTabAt(0)
|
||||
}
|
||||
|
||||
initRecyclerView(
|
||||
model.getMangaContinue(),
|
||||
binding.homeContinueReadingContainer,
|
||||
binding.homeReadingRecyclerView,
|
||||
binding.homeReadingProgressBar,
|
||||
binding.homeReadingEmpty,
|
||||
binding.homeContinueRead
|
||||
)
|
||||
binding.homeReadingBrowseButton.setOnClickListener {
|
||||
bottomBar.selectTabAt(2)
|
||||
}
|
||||
|
||||
initRecyclerView(
|
||||
model.getMangaFav(),
|
||||
binding.homeFavMangaContainer,
|
||||
binding.homeFavMangaRecyclerView,
|
||||
binding.homeFavMangaProgressBar,
|
||||
binding.homeFavMangaEmpty,
|
||||
binding.homeFavManga
|
||||
)
|
||||
|
||||
initRecyclerView(
|
||||
model.getMangaPlanned(),
|
||||
binding.homePlannedMangaContainer,
|
||||
binding.homePlannedMangaRecyclerView,
|
||||
binding.homePlannedMangaProgressBar,
|
||||
binding.homePlannedMangaEmpty,
|
||||
binding.homePlannedManga
|
||||
)
|
||||
binding.homePlannedMangaBrowseButton.setOnClickListener {
|
||||
bottomBar.selectTabAt(2)
|
||||
}
|
||||
|
||||
initRecyclerView(
|
||||
model.getRecommendation(),
|
||||
binding.homeRecommendedContainer,
|
||||
binding.homeRecommendedRecyclerView,
|
||||
binding.homeRecommendedProgressBar,
|
||||
binding.homeRecommendedEmpty,
|
||||
binding.homeRecommended
|
||||
)
|
||||
|
||||
binding.homeUserAvatarContainer.startAnimation(setSlideUp(uiSettings))
|
||||
|
||||
model.empty.observe(viewLifecycleOwner) {
|
||||
binding.homeDantotsuContainer.visibility = if (it == true) View.VISIBLE else View.GONE
|
||||
(binding.homeDantotsuIcon.drawable as Animatable).start()
|
||||
binding.homeDantotsuContainer.startAnimation(setSlideUp(uiSettings))
|
||||
binding.homeDantotsuIcon.setSafeOnClickListener {
|
||||
(binding.homeDantotsuIcon.drawable as Animatable).start()
|
||||
}
|
||||
}
|
||||
|
||||
val array = arrayOf(
|
||||
Runnable { runBlocking { model.setAnimeContinue() } },
|
||||
Runnable { runBlocking { model.setAnimeFav() } },
|
||||
Runnable { runBlocking { model.setAnimePlanned() } },
|
||||
Runnable { runBlocking { model.setMangaContinue() } },
|
||||
Runnable { runBlocking { model.setMangaFav() } },
|
||||
Runnable { runBlocking { model.setMangaPlanned() } },
|
||||
Runnable { runBlocking { model.setRecommendation() } }
|
||||
)
|
||||
|
||||
val containers = arrayOf(
|
||||
binding.homeContinueWatchingContainer,
|
||||
binding.homeFavAnimeContainer,
|
||||
binding.homePlannedAnimeContainer,
|
||||
binding.homeContinueReadingContainer,
|
||||
binding.homeFavMangaContainer,
|
||||
binding.homePlannedMangaContainer,
|
||||
binding.homeRecommendedContainer
|
||||
)
|
||||
|
||||
val live = Refresh.activity.getOrPut(1) { MutableLiveData(false) }
|
||||
live.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
scope.launch {
|
||||
uiSettings = loadData<UserInterfaceSettings>("ui_settings") ?: UserInterfaceSettings()
|
||||
withContext(Dispatchers.IO) {
|
||||
//Get userData First
|
||||
getUserId(requireContext()) {
|
||||
load()
|
||||
}
|
||||
model.loaded = true
|
||||
model.setListImages()
|
||||
var empty = true
|
||||
(array.indices).forEach { i ->
|
||||
if (uiSettings.homeLayoutShow[i]) {
|
||||
array[i].run()
|
||||
empty = false
|
||||
} else withContext(Dispatchers.Main) {
|
||||
containers[i].visibility = View.GONE
|
||||
}
|
||||
}
|
||||
model.empty.postValue(empty)
|
||||
}
|
||||
live.postValue(false)
|
||||
_binding?.homeRefresh?.isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (!model.loaded) Refresh.activity[1]!!.postValue(true)
|
||||
super.onResume()
|
||||
}
|
||||
}
|
28
app/src/main/java/ani/dantotsu/home/LoginFragment.kt
Normal file
28
app/src/main/java/ani/dantotsu/home/LoginFragment.kt
Normal file
|
@ -0,0 +1,28 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.FragmentLoginBinding
|
||||
import ani.dantotsu.openLinkInBrowser
|
||||
|
||||
class LoginFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentLoginBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FragmentLoginBinding.inflate(layoutInflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
binding.loginButton.setOnClickListener { Anilist.loginIntent(requireActivity()) }
|
||||
binding.loginDiscord.setOnClickListener { openLinkInBrowser(getString(R.string.discord)) }
|
||||
binding.loginGithub.setOnClickListener { openLinkInBrowser(getString(R.string.github)) }
|
||||
}
|
||||
}
|
250
app/src/main/java/ani/dantotsu/home/MangaFragment.kt
Normal file
250
app/src/main/java/ani/dantotsu/home/MangaFragment.kt
Normal file
|
@ -0,0 +1,250 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.OvershootInterpolator
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.core.view.updatePaddingRelative
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import ani.dantotsu.R
|
||||
import ani.dantotsu.Refresh
|
||||
import ani.dantotsu.bottomBar
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.connections.anilist.AnilistMangaViewModel
|
||||
import ani.dantotsu.connections.anilist.SearchResults
|
||||
import ani.dantotsu.connections.anilist.getUserId
|
||||
import ani.dantotsu.databinding.FragmentMangaBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
import ani.dantotsu.media.ProgressAdapter
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.px
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.snackString
|
||||
import ani.dantotsu.statusBarHeight
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class MangaFragment : Fragment() {
|
||||
private var _binding: FragmentMangaBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var uiSettings: UserInterfaceSettings = loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
val model: AnilistMangaViewModel by activityViewModels()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
_binding = FragmentMangaBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView();_binding = null
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val scope = viewLifecycleOwner.lifecycleScope
|
||||
|
||||
var height = statusBarHeight
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
val displayCutout = activity?.window?.decorView?.rootWindowInsets?.displayCutout
|
||||
if (displayCutout != null) {
|
||||
if (displayCutout.boundingRects.size > 0) {
|
||||
height = max(
|
||||
statusBarHeight,
|
||||
min(
|
||||
displayCutout.boundingRects[0].width(),
|
||||
displayCutout.boundingRects[0].height()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.mangaRefresh.setSlingshotDistance(height + 128)
|
||||
binding.mangaRefresh.setProgressViewEndTarget(false, height + 128)
|
||||
binding.mangaRefresh.setOnRefreshListener {
|
||||
Refresh.activity[this.hashCode()]!!.postValue(true)
|
||||
}
|
||||
|
||||
binding.mangaPageRecyclerView.updatePaddingRelative(bottom = navBarHeight + 160f.px)
|
||||
|
||||
val mangaPageAdapter = MangaPageAdapter()
|
||||
var loading = true
|
||||
if (model.notSet) {
|
||||
model.notSet = false
|
||||
model.searchResults = SearchResults(
|
||||
"MANGA",
|
||||
isAdult = false,
|
||||
onList = false,
|
||||
results = arrayListOf(),
|
||||
hasNextPage = true,
|
||||
sort = Anilist.sortBy[1]
|
||||
)
|
||||
}
|
||||
val popularAdaptor = MediaAdaptor(1, model.searchResults.results, requireActivity())
|
||||
val progressAdaptor = ProgressAdapter(searched = model.searched)
|
||||
binding.mangaPageRecyclerView.adapter = ConcatAdapter(mangaPageAdapter, popularAdaptor, progressAdaptor)
|
||||
val layout = LinearLayoutManager(requireContext())
|
||||
binding.mangaPageRecyclerView.layoutManager = layout
|
||||
|
||||
var visible = false
|
||||
fun animate() {
|
||||
val start = if (visible) 0f else 1f
|
||||
val end = if (!visible) 0f else 1f
|
||||
ObjectAnimator.ofFloat(binding.mangaPageScrollTop, "scaleX", start, end).apply {
|
||||
duration = 300
|
||||
interpolator = OvershootInterpolator(2f)
|
||||
start()
|
||||
}
|
||||
ObjectAnimator.ofFloat(binding.mangaPageScrollTop, "scaleY", start, end).apply {
|
||||
duration = 300
|
||||
interpolator = OvershootInterpolator(2f)
|
||||
start()
|
||||
}
|
||||
}
|
||||
|
||||
binding.mangaPageScrollTop.setOnClickListener {
|
||||
binding.mangaPageRecyclerView.scrollToPosition(4)
|
||||
binding.mangaPageRecyclerView.smoothScrollToPosition(0)
|
||||
}
|
||||
|
||||
binding.mangaPageRecyclerView.addOnScrollListener(object :
|
||||
RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(v: RecyclerView, dx: Int, dy: Int) {
|
||||
if (!v.canScrollVertically(1)) {
|
||||
if (model.searchResults.hasNextPage && model.searchResults.results.isNotEmpty() && !loading) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
loading = true
|
||||
model.loadNextPage(model.searchResults)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layout.findFirstVisibleItemPosition() > 1 && !visible) {
|
||||
binding.mangaPageScrollTop.visibility = View.VISIBLE
|
||||
visible = true
|
||||
animate()
|
||||
}
|
||||
|
||||
if (!v.canScrollVertically(-1)) {
|
||||
visible = false
|
||||
animate()
|
||||
scope.launch {
|
||||
delay(300)
|
||||
binding.mangaPageScrollTop.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
super.onScrolled(v, dx, dy)
|
||||
}
|
||||
})
|
||||
mangaPageAdapter.ready.observe(viewLifecycleOwner) { i ->
|
||||
if (i == true) {
|
||||
model.getTrendingNovel().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
mangaPageAdapter.updateNovel(MediaAdaptor(0, it, requireActivity()))
|
||||
}
|
||||
}
|
||||
if (mangaPageAdapter.trendingViewPager != null) {
|
||||
mangaPageAdapter.updateHeight()
|
||||
model.getTrending().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
mangaPageAdapter.updateTrending(
|
||||
MediaAdaptor(
|
||||
if (uiSettings.smallView) 3 else 2,
|
||||
it,
|
||||
requireActivity(),
|
||||
viewPager = mangaPageAdapter.trendingViewPager
|
||||
)
|
||||
)
|
||||
mangaPageAdapter.updateAvatar()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.mangaPageScrollTop.translationY = -(navBarHeight + bottomBar.height + bottomBar.marginBottom).toFloat()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var oldIncludeList = true
|
||||
|
||||
mangaPageAdapter.onIncludeListClick = { checked ->
|
||||
oldIncludeList = !checked
|
||||
loading = true
|
||||
model.searchResults.results.clear()
|
||||
popularAdaptor.notifyDataSetChanged()
|
||||
scope.launch(Dispatchers.IO) {
|
||||
model.loadPopular("MANGA", sort = Anilist.sortBy[1], onList = checked)
|
||||
}
|
||||
}
|
||||
|
||||
model.getPopular().observe(viewLifecycleOwner) {
|
||||
if (it != null) {
|
||||
if (oldIncludeList == (it.onList != false)) {
|
||||
val prev = model.searchResults.results.size
|
||||
model.searchResults.results.addAll(it.results)
|
||||
popularAdaptor.notifyItemRangeInserted(prev, it.results.size)
|
||||
} else {
|
||||
model.searchResults.results.addAll(it.results)
|
||||
popularAdaptor.notifyDataSetChanged()
|
||||
oldIncludeList = it.onList ?: true
|
||||
}
|
||||
model.searchResults.onList = it.onList
|
||||
model.searchResults.hasNextPage = it.hasNextPage
|
||||
model.searchResults.page = it.page
|
||||
if (it.hasNextPage)
|
||||
progressAdaptor.bar?.visibility = View.VISIBLE
|
||||
else {
|
||||
snackString(getString(R.string.jobless_message))
|
||||
progressAdaptor.bar?.visibility = View.GONE
|
||||
}
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
fun load() = scope.launch(Dispatchers.Main) {
|
||||
mangaPageAdapter.updateAvatar()
|
||||
}
|
||||
|
||||
val live = Refresh.activity.getOrPut(this.hashCode()) { MutableLiveData(false) }
|
||||
live.observe(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
getUserId(requireContext()) {
|
||||
load()
|
||||
}
|
||||
model.loaded = true
|
||||
model.loadTrending()
|
||||
model.loadTrendingNovel()
|
||||
model.loadPopular("MANGA", sort = Anilist.sortBy[1])
|
||||
}
|
||||
live.postValue(false)
|
||||
_binding?.mangaRefresh?.isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
if (!model.loaded) Refresh.activity[this.hashCode()]!!.postValue(true)
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
}
|
160
app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
Normal file
160
app/src/main/java/ani/dantotsu/home/MangaPageAdapter.kt
Normal file
|
@ -0,0 +1,160 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.LayoutAnimationController
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.view.updatePadding
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2
|
||||
import ani.dantotsu.media.GenreActivity
|
||||
import ani.dantotsu.MediaPageTransformer
|
||||
import ani.dantotsu.connections.anilist.Anilist
|
||||
import ani.dantotsu.databinding.ItemMangaPageBinding
|
||||
import ani.dantotsu.loadData
|
||||
import ani.dantotsu.loadImage
|
||||
import ani.dantotsu.media.MediaAdaptor
|
||||
import ani.dantotsu.media.SearchActivity
|
||||
import ani.dantotsu.px
|
||||
import ani.dantotsu.setSafeOnClickListener
|
||||
import ani.dantotsu.setSlideIn
|
||||
import ani.dantotsu.setSlideUp
|
||||
import ani.dantotsu.settings.SettingsDialogFragment
|
||||
import ani.dantotsu.settings.UserInterfaceSettings
|
||||
import ani.dantotsu.statusBarHeight
|
||||
|
||||
class MangaPageAdapter : RecyclerView.Adapter<MangaPageAdapter.MangaPageViewHolder>() {
|
||||
val ready = MutableLiveData(false)
|
||||
lateinit var binding: ItemMangaPageBinding
|
||||
private var trendHandler: Handler? = null
|
||||
private lateinit var trendRun: Runnable
|
||||
var trendingViewPager: ViewPager2? = null
|
||||
private var uiSettings: UserInterfaceSettings = loadData("ui_settings") ?: UserInterfaceSettings()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MangaPageViewHolder {
|
||||
val binding = ItemMangaPageBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return MangaPageViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: MangaPageViewHolder, position: Int) {
|
||||
binding = holder.binding
|
||||
trendingViewPager = binding.mangaTrendingViewPager
|
||||
|
||||
binding.mangaTitleContainer.updatePadding(top = statusBarHeight)
|
||||
|
||||
if (uiSettings.smallView) binding.mangaTrendingContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
bottomMargin = (-108f).px
|
||||
}
|
||||
|
||||
updateAvatar()
|
||||
|
||||
binding.mangaSearchBar.hint = "MANGA"
|
||||
binding.mangaSearchBarText.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
it.context,
|
||||
Intent(it.context, SearchActivity::class.java).putExtra("type", "MANGA"),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
binding.mangaUserAvatar.setSafeOnClickListener {
|
||||
SettingsDialogFragment().show((it.context as AppCompatActivity).supportFragmentManager, "dialog")
|
||||
}
|
||||
|
||||
binding.mangaSearchBar.setEndIconOnClickListener {
|
||||
binding.mangaSearchBarText.performClick()
|
||||
}
|
||||
|
||||
binding.mangaGenreImage.loadImage("https://s4.anilist.co/file/anilistcdn/media/manga/banner/105778-wk5qQ7zAaTGl.jpg")
|
||||
binding.mangaTopScoreImage.loadImage("https://s4.anilist.co/file/anilistcdn/media/manga/banner/30002-3TuoSMl20fUX.jpg")
|
||||
|
||||
binding.mangaGenre.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
it.context,
|
||||
Intent(it.context, GenreActivity::class.java).putExtra("type", "MANGA"),
|
||||
null
|
||||
)
|
||||
}
|
||||
binding.mangaTopScore.setOnClickListener {
|
||||
ContextCompat.startActivity(
|
||||
it.context,
|
||||
Intent(it.context, SearchActivity::class.java)
|
||||
.putExtra("type", "MANGA")
|
||||
.putExtra("sortBy", Anilist.sortBy[0])
|
||||
.putExtra("search", true),
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
binding.mangaIncludeList.visibility = if(Anilist.userid!=null) View.VISIBLE else View.GONE
|
||||
binding.mangaIncludeList.setOnCheckedChangeListener { _, isChecked ->
|
||||
onIncludeListClick.invoke(isChecked)
|
||||
}
|
||||
|
||||
if (ready.value == false)
|
||||
ready.postValue(true)
|
||||
}
|
||||
|
||||
lateinit var onIncludeListClick : ((Boolean)->Unit)
|
||||
|
||||
override fun getItemCount(): Int = 1
|
||||
|
||||
fun updateHeight() {
|
||||
trendingViewPager!!.updateLayoutParams { height += statusBarHeight }
|
||||
}
|
||||
|
||||
fun updateTrending(adaptor: MediaAdaptor) {
|
||||
binding.mangaTrendingProgressBar.visibility = View.GONE
|
||||
binding.mangaTrendingViewPager.adapter = adaptor
|
||||
binding.mangaTrendingViewPager.offscreenPageLimit = 3
|
||||
binding.mangaTrendingViewPager.getChildAt(0).overScrollMode = RecyclerView.OVER_SCROLL_NEVER
|
||||
binding.mangaTrendingViewPager.setPageTransformer(MediaPageTransformer())
|
||||
trendHandler = Handler(Looper.getMainLooper())
|
||||
trendRun = Runnable {
|
||||
binding.mangaTrendingViewPager.currentItem = binding.mangaTrendingViewPager.currentItem + 1
|
||||
}
|
||||
binding.mangaTrendingViewPager.registerOnPageChangeCallback(
|
||||
object : ViewPager2.OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
super.onPageSelected(position)
|
||||
trendHandler!!.removeCallbacks(trendRun)
|
||||
trendHandler!!.postDelayed(trendRun, 4000)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
binding.mangaTrendingViewPager.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
binding.mangaTitleContainer.startAnimation(setSlideUp(uiSettings))
|
||||
binding.mangaListContainer.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
}
|
||||
|
||||
fun updateNovel(adaptor: MediaAdaptor) {
|
||||
binding.mangaNovelProgressBar.visibility = View.GONE
|
||||
binding.mangaNovelRecyclerView.adapter = adaptor
|
||||
binding.mangaNovelRecyclerView.layoutManager =
|
||||
LinearLayoutManager(binding.mangaNovelRecyclerView.context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.mangaNovelRecyclerView.visibility = View.VISIBLE
|
||||
|
||||
binding.mangaNovel.visibility = View.VISIBLE
|
||||
binding.mangaNovel.startAnimation(setSlideUp(uiSettings))
|
||||
binding.mangaNovelRecyclerView.layoutAnimation = LayoutAnimationController(setSlideIn(uiSettings), 0.25f)
|
||||
binding.mangaPopular.visibility = View.VISIBLE
|
||||
binding.mangaPopular.startAnimation(setSlideUp(uiSettings))
|
||||
}
|
||||
|
||||
fun updateAvatar() {
|
||||
if (Anilist.avatar != null && ready.value == true) {
|
||||
binding.mangaUserAvatar.loadImage(Anilist.avatar)
|
||||
}
|
||||
}
|
||||
|
||||
inner class MangaPageViewHolder(val binding: ItemMangaPageBinding) : RecyclerView.ViewHolder(binding.root)
|
||||
}
|
30
app/src/main/java/ani/dantotsu/home/NoInternet.kt
Normal file
30
app/src/main/java/ani/dantotsu/home/NoInternet.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
package ani.dantotsu.home
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import ani.dantotsu.databinding.ActivityNoInternetBinding
|
||||
import ani.dantotsu.isOnline
|
||||
import ani.dantotsu.navBarHeight
|
||||
import ani.dantotsu.startMainActivity
|
||||
import ani.dantotsu.statusBarHeight
|
||||
|
||||
class NoInternet : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val binding = ActivityNoInternetBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.refreshContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
|
||||
topMargin = statusBarHeight
|
||||
bottomMargin = navBarHeight
|
||||
}
|
||||
binding.refreshButton.setOnClickListener {
|
||||
if (isOnline(this)) {
|
||||
startMainActivity(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue