more searching
This commit is contained in:
parent
3ded6ba87a
commit
c728eae2ba
8 changed files with 190 additions and 35 deletions
|
@ -55,7 +55,7 @@ abstract class BaseParser {
|
||||||
* Isn't necessary to override, but recommended, if you want to improve auto search results
|
* Isn't necessary to override, but recommended, if you want to improve auto search results
|
||||||
* **/
|
* **/
|
||||||
open suspend fun autoSearch(mediaObj: Media): ShowResponse? {
|
open suspend fun autoSearch(mediaObj: Media): ShowResponse? {
|
||||||
var response: ShowResponse? = null//loadSavedShowResponse(mediaObj.id)
|
var response: ShowResponse? = loadSavedShowResponse(mediaObj.id)
|
||||||
if (response != null && this !is OfflineMangaParser) {
|
if (response != null && this !is OfflineMangaParser) {
|
||||||
saveShowResponse(mediaObj.id, response, true)
|
saveShowResponse(mediaObj.id, response, true)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -37,8 +37,9 @@ import kotlinx.coroutines.launch
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class InstalledAnimeExtensionsFragment : Fragment() {
|
class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
|
|
||||||
|
|
||||||
private var _binding: FragmentAnimeExtensionsBinding? = null
|
private var _binding: FragmentAnimeExtensionsBinding? = null
|
||||||
|
@ -207,6 +208,9 @@ class InstalledAnimeExtensionsFragment : Fragment() {
|
||||||
super.onDestroyView();_binding = null
|
super.onDestroyView();_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateContentBasedOnQuery(query: String?) {
|
||||||
|
extensionsAdapter.filter(query ?: "", animeExtensionManager.installedExtensionsFlow.value)
|
||||||
|
}
|
||||||
|
|
||||||
private class AnimeExtensionsAdapter(
|
private class AnimeExtensionsAdapter(
|
||||||
private val onSettingsClicked: (AnimeExtension.Installed) -> Unit,
|
private val onSettingsClicked: (AnimeExtension.Installed) -> Unit,
|
||||||
|
@ -248,6 +252,16 @@ class InstalledAnimeExtensionsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun filter(query: String, currentList: List<AnimeExtension.Installed>) {
|
||||||
|
val filteredList = ArrayList<AnimeExtension.Installed>()
|
||||||
|
for (extension in currentList) {
|
||||||
|
if (extension.name.lowercase(Locale.ROOT).contains(query.lowercase(Locale.ROOT))) {
|
||||||
|
filteredList.add(extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
submitList(filteredList)
|
||||||
|
}
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||||
val extensionVersionTextView: TextView =
|
val extensionVersionTextView: TextView =
|
||||||
|
|
|
@ -38,8 +38,9 @@ import kotlinx.coroutines.launch
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class InstalledMangaExtensionsFragment : Fragment() {
|
class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
private var _binding: FragmentMangaExtensionsBinding? = null
|
private var _binding: FragmentMangaExtensionsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
private lateinit var extensionsRecyclerView: RecyclerView
|
private lateinit var extensionsRecyclerView: RecyclerView
|
||||||
|
@ -187,6 +188,9 @@ class InstalledMangaExtensionsFragment : Fragment() {
|
||||||
super.onDestroyView();_binding = null
|
super.onDestroyView();_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateContentBasedOnQuery(query: String?) {
|
||||||
|
extensionsAdapter.filter(query ?: "", mangaExtensionManager.installedExtensionsFlow.value)
|
||||||
|
}
|
||||||
|
|
||||||
private class MangaExtensionsAdapter(
|
private class MangaExtensionsAdapter(
|
||||||
private val onSettingsClicked: (MangaExtension.Installed) -> Unit,
|
private val onSettingsClicked: (MangaExtension.Installed) -> Unit,
|
||||||
|
@ -230,6 +234,16 @@ class InstalledMangaExtensionsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun filter(query: String, currentList: List<MangaExtension.Installed>) {
|
||||||
|
val filteredList = ArrayList<MangaExtension.Installed>()
|
||||||
|
for (extension in currentList) {
|
||||||
|
if (extension.name.lowercase(Locale.ROOT).contains(query.lowercase(Locale.ROOT))) {
|
||||||
|
filteredList.add(extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
submitList(filteredList)
|
||||||
|
}
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||||
val extensionVersionTextView: TextView =
|
val extensionVersionTextView: TextView =
|
||||||
|
|
|
@ -11,7 +11,6 @@ import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
@ -32,8 +31,9 @@ import kotlinx.coroutines.launch
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
class InstalledNovelExtensionsFragment : Fragment() {
|
class InstalledNovelExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
private var _binding: FragmentNovelExtensionsBinding? = null
|
private var _binding: FragmentNovelExtensionsBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
private lateinit var extensionsRecyclerView: RecyclerView
|
private lateinit var extensionsRecyclerView: RecyclerView
|
||||||
|
@ -124,6 +124,9 @@ class InstalledNovelExtensionsFragment : Fragment() {
|
||||||
super.onDestroyView();_binding = null
|
super.onDestroyView();_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateContentBasedOnQuery(query: String?) {
|
||||||
|
extensionsAdapter.filter(query ?: "", novelExtensionManager.installedExtensionsFlow.value)
|
||||||
|
}
|
||||||
|
|
||||||
private class NovelExtensionsAdapter(
|
private class NovelExtensionsAdapter(
|
||||||
private val onSettingsClicked: (NovelExtension.Installed) -> Unit,
|
private val onSettingsClicked: (NovelExtension.Installed) -> Unit,
|
||||||
|
@ -169,6 +172,16 @@ class InstalledNovelExtensionsFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun filter(query: String, currentList: List<NovelExtension.Installed>) {
|
||||||
|
val filteredList = ArrayList<NovelExtension.Installed>()
|
||||||
|
for (extension in currentList) {
|
||||||
|
if (extension.name.lowercase(Locale.ROOT).contains(query.lowercase(Locale.ROOT))) {
|
||||||
|
filteredList.add(extension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
submitList(filteredList)
|
||||||
|
}
|
||||||
|
|
||||||
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
val extensionNameTextView: TextView = view.findViewById(R.id.extensionNameTextView)
|
||||||
val extensionVersionTextView: TextView =
|
val extensionVersionTextView: TextView =
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ani.dantotsu.settings.paging
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -15,18 +16,25 @@ import androidx.paging.PagingState
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
||||||
import ani.dantotsu.loadData
|
import ani.dantotsu.loadData
|
||||||
import ani.dantotsu.others.LanguageMapper
|
import ani.dantotsu.others.LanguageMapper
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
class AnimeExtensionsViewModelFactory(
|
class AnimeExtensionsViewModelFactory(
|
||||||
|
@ -52,7 +60,13 @@ class AnimeExtensionsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val pagerFlow: Flow<PagingData<AnimeExtension.Available>> = searchQuery.flatMapLatest { query ->
|
val pagerFlow: Flow<PagingData<AnimeExtension.Available>> = combine(
|
||||||
|
animeExtensionManager.availableExtensionsFlow,
|
||||||
|
animeExtensionManager.installedExtensionsFlow,
|
||||||
|
searchQuery
|
||||||
|
) { available, installed, query ->
|
||||||
|
Triple(available, installed, query)
|
||||||
|
}.flatMapLatest { (available, installed, query) ->
|
||||||
Pager(
|
Pager(
|
||||||
PagingConfig(
|
PagingConfig(
|
||||||
pageSize = 15,
|
pageSize = 15,
|
||||||
|
@ -60,27 +74,23 @@ class AnimeExtensionsViewModel(
|
||||||
prefetchDistance = 15
|
prefetchDistance = 15
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
AnimeExtensionPagingSource(
|
AnimeExtensionPagingSource(available, installed, query)
|
||||||
animeExtensionManager.availableExtensionsFlow,
|
|
||||||
animeExtensionManager.installedExtensionsFlow,
|
|
||||||
searchQuery
|
|
||||||
).also { currentPagingSource = it }
|
|
||||||
}.flow
|
}.flow
|
||||||
}.cachedIn(viewModelScope)
|
}.cachedIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnimeExtensionPagingSource(
|
class AnimeExtensionPagingSource(
|
||||||
private val availableExtensionsFlow: StateFlow<List<AnimeExtension.Available>>,
|
private val availableExtensionsFlow: List<AnimeExtension.Available>,
|
||||||
private val installedExtensionsFlow: StateFlow<List<AnimeExtension.Installed>>,
|
private val installedExtensionsFlow: List<AnimeExtension.Installed>,
|
||||||
private val searchQuery: StateFlow<String>
|
private val searchQuery: String
|
||||||
) : PagingSource<Int, AnimeExtension.Available>() {
|
) : PagingSource<Int, AnimeExtension.Available>() {
|
||||||
|
|
||||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AnimeExtension.Available> {
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, AnimeExtension.Available> {
|
||||||
val position = params.key ?: 0
|
val position = params.key ?: 0
|
||||||
val installedExtensions = installedExtensionsFlow.first().map { it.pkgName }.toSet()
|
val installedExtensions = installedExtensionsFlow.map { it.pkgName }.toSet()
|
||||||
val availableExtensions =
|
val availableExtensions =
|
||||||
availableExtensionsFlow.first().filterNot { it.pkgName in installedExtensions }
|
availableExtensionsFlow.filterNot { it.pkgName in installedExtensions }
|
||||||
val query = searchQuery.first()
|
val query = searchQuery
|
||||||
val isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true
|
val isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true
|
||||||
|
|
||||||
val filteredExtensions = if (query.isEmpty()) {
|
val filteredExtensions = if (query.isEmpty()) {
|
||||||
|
@ -160,11 +170,28 @@ class AnimeExtensionAdapter(private val clickListener: OnAnimeInstallClickListen
|
||||||
|
|
||||||
inner class AnimeExtensionViewHolder(private val binding: ItemExtensionAllBinding) :
|
inner class AnimeExtensionViewHolder(private val binding: ItemExtensionAllBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
private val job = Job()
|
||||||
|
private val scope = CoroutineScope(Dispatchers.Main + job)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
binding.closeTextView.setOnClickListener {
|
binding.closeTextView.setOnClickListener {
|
||||||
val extension = getItem(bindingAdapterPosition)
|
val extension = getItem(bindingAdapterPosition)
|
||||||
if (extension != null) {
|
if (extension != null) {
|
||||||
clickListener.onInstallClick(extension)
|
clickListener.onInstallClick(extension)
|
||||||
|
binding.closeTextView.setImageResource(R.drawable.ic_sync)
|
||||||
|
scope.launch {
|
||||||
|
while (isActive) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.closeTextView.animate()
|
||||||
|
.rotationBy(360f)
|
||||||
|
.setDuration(1000)
|
||||||
|
.setInterpolator(LinearInterpolator())
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,6 +204,15 @@ class AnimeExtensionAdapter(private val clickListener: OnAnimeInstallClickListen
|
||||||
binding.extensionNameTextView.text = extension.name
|
binding.extensionNameTextView.text = extension.name
|
||||||
binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
|
binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
job.cancel() // Cancel the coroutine when the view is recycled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewRecycled(holder: AnimeExtensionViewHolder) {
|
||||||
|
super.onViewRecycled(holder)
|
||||||
|
holder.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ani.dantotsu.settings.paging
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -15,18 +16,25 @@ import androidx.paging.PagingState
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
||||||
import ani.dantotsu.loadData
|
import ani.dantotsu.loadData
|
||||||
import ani.dantotsu.others.LanguageMapper
|
import ani.dantotsu.others.LanguageMapper
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||||
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
import eu.kanade.tachiyomi.extension.manga.model.MangaExtension
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class MangaExtensionsViewModelFactory(
|
class MangaExtensionsViewModelFactory(
|
||||||
private val mangaExtensionManager: MangaExtensionManager
|
private val mangaExtensionManager: MangaExtensionManager
|
||||||
|
@ -51,7 +59,13 @@ class MangaExtensionsViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val pagerFlow: Flow<PagingData<MangaExtension.Available>> = searchQuery.flatMapLatest { query ->
|
val pagerFlow: Flow<PagingData<MangaExtension.Available>> = combine(
|
||||||
|
mangaExtensionManager.availableExtensionsFlow,
|
||||||
|
mangaExtensionManager.installedExtensionsFlow,
|
||||||
|
searchQuery
|
||||||
|
) { available, installed, query ->
|
||||||
|
Triple(available, installed, query)
|
||||||
|
}.flatMapLatest { (available, installed, query) ->
|
||||||
Pager(
|
Pager(
|
||||||
PagingConfig(
|
PagingConfig(
|
||||||
pageSize = 15,
|
pageSize = 15,
|
||||||
|
@ -59,28 +73,24 @@ class MangaExtensionsViewModel(
|
||||||
prefetchDistance = 15
|
prefetchDistance = 15
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
MangaExtensionPagingSource(
|
MangaExtensionPagingSource(available, installed, query)
|
||||||
mangaExtensionManager.availableExtensionsFlow,
|
|
||||||
mangaExtensionManager.installedExtensionsFlow,
|
|
||||||
searchQuery
|
|
||||||
).also { currentPagingSource = it }
|
|
||||||
}.flow
|
}.flow
|
||||||
}.cachedIn(viewModelScope)
|
}.cachedIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MangaExtensionPagingSource(
|
class MangaExtensionPagingSource(
|
||||||
private val availableExtensionsFlow: StateFlow<List<MangaExtension.Available>>,
|
private val availableExtensionsFlow: List<MangaExtension.Available>,
|
||||||
private val installedExtensionsFlow: StateFlow<List<MangaExtension.Installed>>,
|
private val installedExtensionsFlow: List<MangaExtension.Installed>,
|
||||||
private val searchQuery: StateFlow<String>
|
private val searchQuery: String
|
||||||
) : PagingSource<Int, MangaExtension.Available>() {
|
) : PagingSource<Int, MangaExtension.Available>() {
|
||||||
|
|
||||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MangaExtension.Available> {
|
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, MangaExtension.Available> {
|
||||||
val position = params.key ?: 0
|
val position = params.key ?: 0
|
||||||
val installedExtensions = installedExtensionsFlow.first().map { it.pkgName }.toSet()
|
val installedExtensions = installedExtensionsFlow.map { it.pkgName }.toSet()
|
||||||
val availableExtensions =
|
val availableExtensions =
|
||||||
availableExtensionsFlow.first().filterNot { it.pkgName in installedExtensions }
|
availableExtensionsFlow.filterNot { it.pkgName in installedExtensions }
|
||||||
val query = searchQuery.first()
|
val query = searchQuery
|
||||||
val isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true
|
val isNsfwEnabled: Boolean = loadData("NFSWExtension") ?: true
|
||||||
val filteredExtensions = if (query.isEmpty()) {
|
val filteredExtensions = if (query.isEmpty()) {
|
||||||
availableExtensions
|
availableExtensions
|
||||||
|
@ -157,11 +167,28 @@ class MangaExtensionAdapter(private val clickListener: OnMangaInstallClickListen
|
||||||
|
|
||||||
inner class MangaExtensionViewHolder(private val binding: ItemExtensionAllBinding) :
|
inner class MangaExtensionViewHolder(private val binding: ItemExtensionAllBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
private val job = Job()
|
||||||
|
private val scope = CoroutineScope(Dispatchers.Main + job)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
binding.closeTextView.setOnClickListener {
|
binding.closeTextView.setOnClickListener {
|
||||||
val extension = getItem(bindingAdapterPosition)
|
val extension = getItem(bindingAdapterPosition)
|
||||||
if (extension != null) {
|
if (extension != null) {
|
||||||
clickListener.onInstallClick(extension)
|
clickListener.onInstallClick(extension)
|
||||||
|
binding.closeTextView.setImageResource(R.drawable.ic_sync)
|
||||||
|
scope.launch {
|
||||||
|
while (isActive) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.closeTextView.animate()
|
||||||
|
.rotationBy(360f)
|
||||||
|
.setDuration(1000)
|
||||||
|
.setInterpolator(LinearInterpolator())
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,6 +200,15 @@ class MangaExtensionAdapter(private val clickListener: OnMangaInstallClickListen
|
||||||
binding.extensionNameTextView.text = extension.name
|
binding.extensionNameTextView.text = extension.name
|
||||||
binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
|
binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
job.cancel() // Cancel the coroutine when the view is recycled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewRecycled(holder: MangaExtensionViewHolder) {
|
||||||
|
super.onViewRecycled(holder)
|
||||||
|
holder.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ani.dantotsu.settings.paging
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.view.animation.LinearInterpolator
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -15,19 +16,25 @@ import androidx.paging.PagingState
|
||||||
import androidx.paging.cachedIn
|
import androidx.paging.cachedIn
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
import ani.dantotsu.databinding.ItemExtensionAllBinding
|
||||||
import ani.dantotsu.loadData
|
import ani.dantotsu.loadData
|
||||||
import ani.dantotsu.others.LanguageMapper
|
import ani.dantotsu.others.LanguageMapper
|
||||||
import ani.dantotsu.parsers.novel.NovelExtension
|
import ani.dantotsu.parsers.novel.NovelExtension
|
||||||
import ani.dantotsu.parsers.novel.NovelExtensionManager
|
import ani.dantotsu.parsers.novel.NovelExtensionManager
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.first
|
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
|
import kotlinx.coroutines.isActive
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
|
||||||
class NovelExtensionsViewModelFactory(
|
class NovelExtensionsViewModelFactory(
|
||||||
|
@ -163,11 +170,28 @@ class NovelExtensionAdapter(private val clickListener: OnNovelInstallClickListen
|
||||||
|
|
||||||
inner class NovelExtensionViewHolder(private val binding: ItemExtensionAllBinding) :
|
inner class NovelExtensionViewHolder(private val binding: ItemExtensionAllBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root) {
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
private val job = Job()
|
||||||
|
private val scope = CoroutineScope(Dispatchers.Main + job)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
binding.closeTextView.setOnClickListener {
|
binding.closeTextView.setOnClickListener {
|
||||||
val extension = getItem(bindingAdapterPosition)
|
val extension = getItem(bindingAdapterPosition)
|
||||||
if (extension != null) {
|
if (extension != null) {
|
||||||
clickListener.onInstallClick(extension)
|
clickListener.onInstallClick(extension)
|
||||||
|
binding.closeTextView.setImageResource(R.drawable.ic_sync)
|
||||||
|
scope.launch {
|
||||||
|
while (isActive) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
binding.closeTextView.animate()
|
||||||
|
.rotationBy(360f)
|
||||||
|
.setDuration(1000)
|
||||||
|
.setInterpolator(LinearInterpolator())
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
delay(1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,6 +203,15 @@ class NovelExtensionAdapter(private val clickListener: OnNovelInstallClickListen
|
||||||
binding.extensionNameTextView.text = extension.name
|
binding.extensionNameTextView.text = extension.name
|
||||||
binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
|
binding.extensionVersionTextView.text = "$lang ${extension.versionName} $nsfw"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
job.cancel() // Cancel the coroutine when the view is recycled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewRecycled(holder: NovelExtensionViewHolder) {
|
||||||
|
super.onViewRecycled(holder)
|
||||||
|
holder.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,5 +139,14 @@
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:layout_weight="1" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/fragmentExtensionsContainer"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_weight="1">
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
Loading…
Add table
Add a link
Reference in a new issue