package ani.dantotsu.media import android.annotation.SuppressLint import android.os.Bundle import android.os.Parcelable import android.view.View import android.view.WindowManager import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity import androidx.core.view.isVisible import androidx.core.view.updatePaddingRelative import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import ani.dantotsu.connections.anilist.Anilist import ani.dantotsu.connections.anilist.AnilistSearch import ani.dantotsu.connections.anilist.SearchResults import ani.dantotsu.databinding.ActivitySearchBinding import ani.dantotsu.initActivity import ani.dantotsu.navBarHeight import ani.dantotsu.px import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight import ani.dantotsu.themes.ThemeManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import java.util.Timer import java.util.TimerTask class SearchActivity : AppCompatActivity() { private lateinit var binding: ActivitySearchBinding private val scope = lifecycleScope val model: AnilistSearch by viewModels() var style: Int = 0 private var screenWidth: Float = 0f private lateinit var mediaAdaptor: MediaAdaptor private lateinit var progressAdapter: ProgressAdapter private lateinit var concatAdapter: ConcatAdapter private lateinit var headerAdaptor: SearchAdapter lateinit var result: SearchResults lateinit var updateChips: (() -> Unit) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ThemeManager(this).applyTheme() binding = ActivitySearchBinding.inflate(layoutInflater) setContentView(binding.root) initActivity(this) screenWidth = resources.displayMetrics.run { widthPixels / density } binding.searchRecyclerView.updatePaddingRelative( top = statusBarHeight, bottom = navBarHeight + 80f.px ) style = PrefManager.getVal(PrefName.SearchStyle) var listOnly: Boolean? = intent.getBooleanExtra("listOnly", false) if (!listOnly!!) listOnly = null val notSet = model.notSet if (model.notSet) { model.notSet = false model.searchResults = SearchResults( intent.getStringExtra("type") ?: "ANIME", isAdult = if (Anilist.adult) intent.getBooleanExtra("hentai", false) else false, onList = listOnly, search = intent.getStringExtra("query"), genres = intent.getStringExtra("genre")?.let { mutableListOf(it) }, tags = intent.getStringExtra("tag")?.let { mutableListOf(it) }, sort = intent.getStringExtra("sortBy"), status = intent.getStringExtra("status"), source = intent.getStringExtra("source"), countryOfOrigin = intent.getStringExtra("country"), season = intent.getStringExtra("season"), seasonYear = if (intent.getStringExtra("type") == "ANIME") intent.getStringExtra("seasonYear") ?.toIntOrNull() else null, startYear = if (intent.getStringExtra("type") == "MANGA") intent.getStringExtra("seasonYear") ?.toIntOrNull() else null, results = mutableListOf(), hasNextPage = false ) } result = model.searchResults progressAdapter = ProgressAdapter(searched = model.searched) mediaAdaptor = MediaAdaptor(style, model.searchResults.results, this, matchParent = true) headerAdaptor = SearchAdapter(this, model.searchResults.type) val gridSize = (screenWidth / 120f).toInt() val gridLayoutManager = GridLayoutManager(this, gridSize) gridLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { return when (position) { 0 -> gridSize concatAdapter.itemCount - 1 -> gridSize else -> when (style) { 0 -> 1 else -> gridSize } } } } concatAdapter = ConcatAdapter(headerAdaptor, mediaAdaptor, progressAdapter) binding.searchRecyclerView.layoutManager = gridLayoutManager binding.searchRecyclerView.adapter = concatAdapter binding.searchRecyclerView.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) { model.loadNextPage(model.searchResults) } } } super.onScrolled(v, dx, dy) } }) model.getSearch().observe(this) { if (it != null) { model.searchResults.apply { onList = it.onList isAdult = it.isAdult perPage = it.perPage search = it.search sort = it.sort genres = it.genres excludedGenres = it.excludedGenres excludedTags = it.excludedTags tags = it.tags season = it.season startYear = it.startYear seasonYear = it.seasonYear status = it.status source = it.source format = it.format countryOfOrigin = it.countryOfOrigin page = it.page hasNextPage = it.hasNextPage } val prev = model.searchResults.results.size model.searchResults.results.addAll(it.results) mediaAdaptor.notifyItemRangeInserted(prev, it.results.size) progressAdapter.bar?.isVisible = it.hasNextPage } } progressAdapter.ready.observe(this) { if (it == true) { if (!notSet) { if (!model.searched) { model.searched = true headerAdaptor.search?.run() } } else headerAdaptor.requestFocus?.run() if (intent.getBooleanExtra("search", false)) { window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED) search() } } } } fun emptyMediaAdapter() { searchTimer.cancel() searchTimer.purge() mediaAdaptor.notifyItemRangeRemoved(0, model.searchResults.results.size) model.searchResults.results.clear() progressAdapter.bar?.visibility = View.GONE } private var searchTimer = Timer() private var loading = false fun search() { headerAdaptor.setHistoryVisibility(false) val size = model.searchResults.results.size model.searchResults.results.clear() binding.searchRecyclerView.post { mediaAdaptor.notifyItemRangeRemoved(0, size) } progressAdapter.bar?.visibility = View.VISIBLE searchTimer.cancel() searchTimer.purge() val timerTask: TimerTask = object : TimerTask() { override fun run() { scope.launch(Dispatchers.IO) { loading = true model.loadSearch(result) loading = false } } } searchTimer = Timer() searchTimer.schedule(timerTask, 500) } @SuppressLint("NotifyDataSetChanged") fun recycler() { mediaAdaptor.type = style mediaAdaptor.notifyDataSetChanged() } var state: Parcelable? = null override fun onPause() { if (this::headerAdaptor.isInitialized) { headerAdaptor.addHistory() } super.onPause() state = binding.searchRecyclerView.layoutManager?.onSaveInstanceState() } override fun onResume() { super.onResume() binding.searchRecyclerView.layoutManager?.onRestoreInstanceState(state) } }