Dantotsu/app/src/main/java/ani/dantotsu/media/SearchActivity.kt
2024-04-19 06:03:40 -05:00

233 lines
No EOL
8.5 KiB
Kotlin

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)
}
}