package com.streamflixreborn.streamflix.fragments.genre import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.streamflixreborn.streamflix.adapters.AppAdapter import com.streamflixreborn.streamflix.database.AppDatabase import com.streamflixreborn.streamflix.databinding.FragmentGenreMobileBinding import com.streamflixreborn.streamflix.databinding.HeaderGenreMobileBinding import com.streamflixreborn.streamflix.models.Genre import com.streamflixreborn.streamflix.models.Movie import com.streamflixreborn.streamflix.models.TvShow import com.streamflixreborn.streamflix.ui.SpacingItemDecoration import com.streamflixreborn.streamflix.utils.CacheUtils import com.streamflixreborn.streamflix.utils.dp import com.streamflixreborn.streamflix.utils.viewModelsFactory import kotlinx.coroutines.launch class GenreMobileFragment : Fragment() { private var hasAutoCleared409: Boolean = false private var _binding: FragmentGenreMobileBinding? = null private val binding get() = _binding!! private val args by navArgs() private val database by lazy { AppDatabase.getInstance(requireContext()) } private val viewModel by viewModelsFactory { GenreViewModel(args.id, database) } private val appAdapter = AppAdapter() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentGenreMobileBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initializeGenre() viewLifecycleOwner.lifecycleScope.launch { viewModel.state.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED).collect { state -> when (state) { GenreViewModel.State.Loading -> binding.isLoading.apply { root.visibility = View.VISIBLE pbIsLoading.visibility = View.VISIBLE gIsLoadingRetry.visibility = View.GONE } GenreViewModel.State.LoadingMore -> appAdapter.isLoading = true is GenreViewModel.State.SuccessLoading -> { displayGenre(state.genre, state.hasMore) appAdapter.isLoading = false binding.isLoading.root.visibility = View.GONE } is GenreViewModel.State.FailedLoading -> { val code = (state.error as? retrofit2.HttpException)?.code() if (code == 409 && !hasAutoCleared409) { hasAutoCleared409 = true CacheUtils.clearAppCache(requireContext()) android.widget.Toast.makeText(requireContext(), getString(com.streamflixreborn.streamflix.R.string.clear_cache_done_409), android.widget.Toast.LENGTH_SHORT).show() viewModel.getGenre(args.id) return@collect } Toast.makeText( requireContext(), state.error.message ?: "", Toast.LENGTH_SHORT ).show() if (appAdapter.isLoading) { appAdapter.isLoading = false } else { binding.isLoading.apply { pbIsLoading.visibility = View.GONE gIsLoadingRetry.visibility = View.VISIBLE val doRetry = { viewModel.getGenre(args.id) } btnIsLoadingRetry.setOnClickListener { doRetry() } btnIsLoadingClearCache.setOnClickListener { CacheUtils.clearAppCache(requireContext()) android.widget.Toast.makeText(requireContext(), getString(com.streamflixreborn.streamflix.R.string.clear_cache_done), android.widget.Toast.LENGTH_SHORT).show() doRetry() } } } } } } } } override fun onDestroyView() { super.onDestroyView() _binding = null } private fun initializeGenre() { binding.rvGenre.apply { layoutManager = GridLayoutManager(context, 3).also { it.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { val viewType = appAdapter.getItemViewType(position) return when (AppAdapter.Type.entries[viewType]) { AppAdapter.Type.HEADER -> it.spanCount else -> 1 } } } } adapter = appAdapter.apply { stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY } addItemDecoration( SpacingItemDecoration(10.dp(requireContext())) ) } } private fun displayGenre(genre: Genre, hasMore: Boolean) { appAdapter.setHeader( binding = { parent -> HeaderGenreMobileBinding.inflate( LayoutInflater.from(parent.context), parent, false ) }, bind = { binding -> binding.tvGenreName.text = genre.name.takeIf { it.isNotEmpty() } ?: args.name } ) appAdapter.submitList(genre.shows.onEach { when (it) { is Movie -> it.itemType = AppAdapter.Type.MOVIE_GRID_MOBILE_ITEM is TvShow -> it.itemType = AppAdapter.Type.TV_SHOW_GRID_MOBILE_ITEM } }) if (hasMore) { appAdapter.setOnLoadMoreListener { viewModel.loadMoreGenreShows() } } else { appAdapter.setOnLoadMoreListener(null) } } }