sortable sources
This commit is contained in:
parent
402e0576c8
commit
d3f097f675
8 changed files with 150 additions and 155 deletions
|
@ -3,18 +3,24 @@ package ani.dantotsu.parsers
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import ani.dantotsu.Lazier
|
import ani.dantotsu.Lazier
|
||||||
import ani.dantotsu.lazyList
|
import ani.dantotsu.lazyList
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.settings.saving.PrefManager.asLiveString
|
||||||
|
import ani.dantotsu.settings.saving.PrefManager.asLiveStringSet
|
||||||
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
object AnimeSources : WatchSources() {
|
object AnimeSources : WatchSources() {
|
||||||
override var list: List<Lazier<BaseParser>> = emptyList()
|
override var list: List<Lazier<BaseParser>> = emptyList()
|
||||||
var pinnedAnimeSources: Set<String> = emptySet()
|
var pinnedAnimeSources: List<String> = emptyList()
|
||||||
|
|
||||||
suspend fun init(fromExtensions: StateFlow<List<AnimeExtension.Installed>>, context: Context) {
|
suspend fun init(fromExtensions: StateFlow<List<AnimeExtension.Installed>>, context: Context) {
|
||||||
pinnedAnimeSources = PrefManager.getVal(PrefName.PinnedAnimeSources)
|
pinnedAnimeSources = PrefManager.getNullableVal<List<String>>(PrefName.AnimeSourcesOrder, null)
|
||||||
|
?: emptyList()
|
||||||
|
|
||||||
// Initialize with the first value from StateFlow
|
// Initialize with the first value from StateFlow
|
||||||
val initialExtensions = fromExtensions.first()
|
val initialExtensions = fromExtensions.first()
|
||||||
|
@ -53,14 +59,17 @@ object AnimeSources : WatchSources() {
|
||||||
|
|
||||||
private fun sortPinnedAnimeSources(
|
private fun sortPinnedAnimeSources(
|
||||||
Sources: List<Lazier<BaseParser>>,
|
Sources: List<Lazier<BaseParser>>,
|
||||||
pinnedAnimeSources: Set<String>
|
pinnedAnimeSources: List<String>
|
||||||
): List<Lazier<BaseParser>> {
|
): List<Lazier<BaseParser>> {
|
||||||
//find the pinned sources
|
val pinnedSourcesMap = Sources.filter { pinnedAnimeSources.contains(it.name) }
|
||||||
val pinnedSources = Sources.filter { pinnedAnimeSources.contains(it.name) }
|
.associateBy { it.name }
|
||||||
|
val orderedPinnedSources = pinnedAnimeSources.mapNotNull { name ->
|
||||||
|
pinnedSourcesMap[name]
|
||||||
|
}
|
||||||
//find the unpinned sources
|
//find the unpinned sources
|
||||||
val unpinnedSources = Sources.filter { !pinnedAnimeSources.contains(it.name) }
|
val unpinnedSources = Sources.filter { !pinnedAnimeSources.contains(it.name) }
|
||||||
//put the pinned sources at the top of the list
|
//put the pinned sources at the top of the list
|
||||||
return pinnedSources + unpinnedSources
|
return orderedPinnedSources + unpinnedSources
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,11 @@ import kotlinx.coroutines.flow.first
|
||||||
|
|
||||||
object MangaSources : MangaReadSources() {
|
object MangaSources : MangaReadSources() {
|
||||||
override var list: List<Lazier<BaseParser>> = emptyList()
|
override var list: List<Lazier<BaseParser>> = emptyList()
|
||||||
var pinnedMangaSources: Set<String> = emptySet()
|
var pinnedMangaSources: List<String> = emptyList()
|
||||||
|
|
||||||
suspend fun init(fromExtensions: StateFlow<List<MangaExtension.Installed>>) {
|
suspend fun init(fromExtensions: StateFlow<List<MangaExtension.Installed>>) {
|
||||||
pinnedMangaSources = PrefManager.getVal(PrefName.PinnedMangaSources)
|
pinnedMangaSources = PrefManager.getNullableVal<List<String>>(PrefName.MangaSourcesOrder, null)
|
||||||
|
?: emptyList()
|
||||||
|
|
||||||
// Initialize with the first value from StateFlow
|
// Initialize with the first value from StateFlow
|
||||||
val initialExtensions = fromExtensions.first()
|
val initialExtensions = fromExtensions.first()
|
||||||
|
@ -52,14 +53,17 @@ object MangaSources : MangaReadSources() {
|
||||||
|
|
||||||
private fun sortPinnedMangaSources(
|
private fun sortPinnedMangaSources(
|
||||||
Sources: List<Lazier<BaseParser>>,
|
Sources: List<Lazier<BaseParser>>,
|
||||||
pinnedMangaSources: Set<String>
|
pinnedMangaSources: List<String>
|
||||||
): List<Lazier<BaseParser>> {
|
): List<Lazier<BaseParser>> {
|
||||||
//find the pinned sources
|
val pinnedSourcesMap = Sources.filter { pinnedMangaSources.contains(it.name) }
|
||||||
val pinnedSources = Sources.filter { pinnedMangaSources.contains(it.name) }
|
.associateBy { it.name }
|
||||||
|
val orderedPinnedSources = pinnedMangaSources.mapNotNull { name ->
|
||||||
|
pinnedSourcesMap[name]
|
||||||
|
}
|
||||||
//find the unpinned sources
|
//find the unpinned sources
|
||||||
val unpinnedSources = Sources.filter { !pinnedMangaSources.contains(it.name) }
|
val unpinnedSources = Sources.filter { !pinnedMangaSources.contains(it.name) }
|
||||||
//put the pinned sources at the top of the list
|
//put the pinned sources at the top of the list
|
||||||
return pinnedSources + unpinnedSources
|
return orderedPinnedSources + unpinnedSources
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@ import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.view.GestureDetector
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
@ -17,16 +19,19 @@ import androidx.core.app.NotificationCompat
|
||||||
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
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
import ani.dantotsu.databinding.FragmentAnimeExtensionsBinding
|
||||||
|
import ani.dantotsu.logger
|
||||||
import ani.dantotsu.others.LanguageMapper
|
import ani.dantotsu.others.LanguageMapper
|
||||||
|
import ani.dantotsu.parsers.AnimeSources
|
||||||
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
|
import ani.dantotsu.settings.extensionprefs.AnimeSourcePreferencesFragment
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.snackString
|
import ani.dantotsu.snackString
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
|
@ -39,8 +44,10 @@ 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.Collections
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
|
|
||||||
class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,6 +181,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
}, skipIcons
|
}, skipIcons
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
@ -185,16 +193,53 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
extensionsRecyclerView.adapter = extensionsAdapter
|
extensionsRecyclerView.adapter = extensionsAdapter
|
||||||
|
|
||||||
|
val itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(
|
||||||
|
ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) {
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
extensionsAdapter.onMove(viewHolder.adapterPosition, target.adapterPosition)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
|
||||||
|
|
||||||
|
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||||
|
super.onSelectedChanged(viewHolder, actionState)
|
||||||
|
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||||
|
viewHolder?.itemView?.elevation = 8f
|
||||||
|
viewHolder?.itemView?.translationZ = 8f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
viewHolder.itemView.elevation = 0f
|
||||||
|
viewHolder.itemView.translationZ = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(extensionsRecyclerView)
|
||||||
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
animeExtensionManager.installedExtensionsFlow.collect { extensions ->
|
animeExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||||
extensionsAdapter.updateData(extensions)
|
extensionsAdapter.updateData(sortToAnimeSourcesList(extensions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val extensionsRecyclerView: RecyclerView = binding.allAnimeExtensionsRecyclerView
|
val extensionsRecyclerView: RecyclerView = binding.allAnimeExtensionsRecyclerView
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun sortToAnimeSourcesList(inpt: List<AnimeExtension.Installed>): List<AnimeExtension.Installed> {
|
||||||
|
val sourcesMap = inpt.associateBy { it.name }
|
||||||
|
val orderedSources = AnimeSources.pinnedAnimeSources.mapNotNull { name ->
|
||||||
|
sourcesMap[name]
|
||||||
|
}
|
||||||
|
return orderedSources + inpt.filter { !AnimeSources.pinnedAnimeSources.contains(it.name) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView();_binding = null
|
super.onDestroyView();_binding = null
|
||||||
}
|
}
|
||||||
|
@ -211,8 +256,21 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
DIFF_CALLBACK_INSTALLED
|
DIFF_CALLBACK_INSTALLED
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val data: MutableList<AnimeExtension.Installed> = mutableListOf()
|
||||||
|
|
||||||
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
fun updateData(newExtensions: List<AnimeExtension.Installed>) {
|
||||||
submitList(newExtensions) // Use submitList instead of manual list handling
|
submitList(newExtensions)
|
||||||
|
data.clear()
|
||||||
|
data.addAll(newExtensions)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onMove(fromPosition: Int, toPosition: Int) {
|
||||||
|
Collections.swap(data, fromPosition, toPosition)
|
||||||
|
val map = data.map { it.name }.toList()
|
||||||
|
PrefManager.setVal(PrefName.AnimeSourcesOrder, map)
|
||||||
|
AnimeSources.pinnedAnimeSources = map
|
||||||
|
AnimeSources.performReorderAnimeSources()
|
||||||
|
notifyItemMoved(fromPosition, toPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -221,7 +279,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val extension = getItem(position) // Use getItem() from ListAdapter
|
val extension = getItem(position) // Use getItem() from ListAdapter
|
||||||
val nsfw = if (extension.isNsfw) "(18+)" else ""
|
val nsfw = if (extension.isNsfw) "(18+)" else ""
|
||||||
|
@ -242,7 +300,7 @@ class InstalledAnimeExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
holder.settingsImageView.setOnClickListener {
|
holder.settingsImageView.setOnClickListener {
|
||||||
onSettingsClicked(extension)
|
onSettingsClicked(extension)
|
||||||
}
|
}
|
||||||
holder.card.setOnLongClickListener {
|
holder.closeTextView.setOnLongClickListener {
|
||||||
onUninstallClicked(extension, true)
|
onUninstallClicked(extension, true)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
@ -18,6 +19,7 @@ import androidx.core.app.NotificationCompat
|
||||||
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
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
@ -25,6 +27,7 @@ import androidx.viewpager2.widget.ViewPager2
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.databinding.FragmentMangaExtensionsBinding
|
import ani.dantotsu.databinding.FragmentMangaExtensionsBinding
|
||||||
import ani.dantotsu.others.LanguageMapper
|
import ani.dantotsu.others.LanguageMapper
|
||||||
|
import ani.dantotsu.parsers.MangaSources
|
||||||
import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
|
import ani.dantotsu.settings.extensionprefs.MangaSourcePreferencesFragment
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
|
@ -33,6 +36,7 @@ import com.google.android.material.tabs.TabLayout
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import eu.kanade.tachiyomi.data.notification.Notifications
|
import eu.kanade.tachiyomi.data.notification.Notifications
|
||||||
|
import eu.kanade.tachiyomi.extension.anime.model.AnimeExtension
|
||||||
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 eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
|
@ -40,6 +44,7 @@ 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.Collections
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
|
@ -184,16 +189,52 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
extensionsRecyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||||
extensionsRecyclerView.adapter = extensionsAdapter
|
extensionsRecyclerView.adapter = extensionsAdapter
|
||||||
|
|
||||||
|
val itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(
|
||||||
|
ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) {
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
extensionsAdapter.onMove(viewHolder.adapterPosition, target.adapterPosition)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {}
|
||||||
|
|
||||||
|
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||||
|
super.onSelectedChanged(viewHolder, actionState)
|
||||||
|
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||||
|
viewHolder?.itemView?.elevation = 8f
|
||||||
|
viewHolder?.itemView?.translationZ = 8f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
viewHolder.itemView.elevation = 0f
|
||||||
|
viewHolder.itemView.translationZ = 0f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ItemTouchHelper(itemTouchHelperCallback).attachToRecyclerView(extensionsRecyclerView)
|
||||||
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
mangaExtensionManager.installedExtensionsFlow.collect { extensions ->
|
mangaExtensionManager.installedExtensionsFlow.collect { extensions ->
|
||||||
extensionsAdapter.updateData(extensions)
|
extensionsAdapter.updateData(sortToMangaSourcesList(extensions))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val extensionsRecyclerView: RecyclerView = binding.allMangaExtensionsRecyclerView
|
val extensionsRecyclerView: RecyclerView = binding.allMangaExtensionsRecyclerView
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun sortToMangaSourcesList(inpt: List<MangaExtension.Installed>): List<MangaExtension.Installed> {
|
||||||
|
val sourcesMap = inpt.associateBy { it.name }
|
||||||
|
val orderedSources = MangaSources.pinnedMangaSources.mapNotNull { name ->
|
||||||
|
sourcesMap[name]
|
||||||
|
}
|
||||||
|
return orderedSources + inpt.filter { !MangaSources.pinnedMangaSources.contains(it.name) }
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
super.onDestroyView();_binding = null
|
super.onDestroyView();_binding = null
|
||||||
}
|
}
|
||||||
|
@ -205,15 +246,17 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
private class MangaExtensionsAdapter(
|
private class MangaExtensionsAdapter(
|
||||||
private val onSettingsClicked: (MangaExtension.Installed) -> Unit,
|
private val onSettingsClicked: (MangaExtension.Installed) -> Unit,
|
||||||
private val onUninstallClicked: (MangaExtension.Installed, Boolean) -> Unit,
|
private val onUninstallClicked: (MangaExtension.Installed, Boolean) -> Unit,
|
||||||
skipIcons: Boolean
|
val skipIcons: Boolean
|
||||||
) : ListAdapter<MangaExtension.Installed, MangaExtensionsAdapter.ViewHolder>(
|
) : ListAdapter<MangaExtension.Installed, MangaExtensionsAdapter.ViewHolder>(
|
||||||
DIFF_CALLBACK_INSTALLED
|
DIFF_CALLBACK_INSTALLED
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val skipIcons = skipIcons
|
private val data: MutableList<MangaExtension.Installed> = mutableListOf()
|
||||||
|
|
||||||
fun updateData(newExtensions: List<MangaExtension.Installed>) {
|
fun updateData(newExtensions: List<MangaExtension.Installed>) {
|
||||||
submitList(newExtensions) // Use submitList instead of manual list handling
|
submitList(newExtensions)
|
||||||
|
data.clear()
|
||||||
|
data.addAll(newExtensions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
@ -222,7 +265,16 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
return ViewHolder(view)
|
return ViewHolder(view)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
fun onMove(fromPosition: Int, toPosition: Int) {
|
||||||
|
Collections.swap(data, fromPosition, toPosition)
|
||||||
|
val map = data.map { it.name }.toList()
|
||||||
|
PrefManager.setVal(PrefName.MangaSourcesOrder, map)
|
||||||
|
MangaSources.pinnedMangaSources = map
|
||||||
|
MangaSources.performReorderMangaSources()
|
||||||
|
notifyItemMoved(fromPosition, toPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
val extension = getItem(position) // Use getItem() from ListAdapter
|
val extension = getItem(position) // Use getItem() from ListAdapter
|
||||||
val nsfw = if (extension.isNsfw) "(18+)" else ""
|
val nsfw = if (extension.isNsfw) "(18+)" else ""
|
||||||
|
@ -243,11 +295,6 @@ class InstalledMangaExtensionsFragment : Fragment(), SearchQueryHandler {
|
||||||
holder.settingsImageView.setOnClickListener {
|
holder.settingsImageView.setOnClickListener {
|
||||||
onSettingsClicked(extension)
|
onSettingsClicked(extension)
|
||||||
}
|
}
|
||||||
|
|
||||||
holder.card.setOnLongClickListener {
|
|
||||||
onUninstallClicked(extension, true)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun filter(query: String, currentList: List<MangaExtension.Installed>) {
|
fun filter(query: String, currentList: List<MangaExtension.Installed>) {
|
||||||
|
|
|
@ -212,37 +212,6 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
||||||
.show(this, tag)
|
.show(this, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.settingsPinnedAnimeSources.setOnClickListener {
|
|
||||||
val animeSourcesWithoutDownloadsSource =
|
|
||||||
AnimeSources.list.filter { it.name != "Downloaded" }
|
|
||||||
val names = animeSourcesWithoutDownloadsSource.map { it.name }
|
|
||||||
val pinnedSourcesBoolean =
|
|
||||||
animeSourcesWithoutDownloadsSource.map { it.name in AnimeSources.pinnedAnimeSources }
|
|
||||||
val pinnedSourcesOriginal: Set<String> = PrefManager.getVal(PrefName.PinnedAnimeSources)
|
|
||||||
val pinnedSources = pinnedSourcesOriginal.toMutableSet()
|
|
||||||
val alertDialog = AlertDialog.Builder(this, R.style.MyPopup)
|
|
||||||
.setTitle("Pinned Anime Sources")
|
|
||||||
.setMultiChoiceItems(
|
|
||||||
names.toTypedArray(),
|
|
||||||
pinnedSourcesBoolean.toBooleanArray()
|
|
||||||
) { _, which, isChecked ->
|
|
||||||
if (isChecked) {
|
|
||||||
pinnedSources.add(AnimeSources.names[which])
|
|
||||||
} else {
|
|
||||||
pinnedSources.remove(AnimeSources.names[which])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setPositiveButton("OK") { dialog, _ ->
|
|
||||||
PrefManager.setVal(PrefName.PinnedAnimeSources, pinnedSources)
|
|
||||||
AnimeSources.pinnedAnimeSources = pinnedSources
|
|
||||||
AnimeSources.performReorderAnimeSources()
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
alertDialog.show()
|
|
||||||
alertDialog.window?.setDimAmount(0.8f)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.settingsPlayer.setOnClickListener {
|
binding.settingsPlayer.setOnClickListener {
|
||||||
startActivity(Intent(this, PlayerSettingsActivity::class.java))
|
startActivity(Intent(this, PlayerSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
@ -472,37 +441,6 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
||||||
PrefManager.setVal(PrefName.SettingsPreferDub, isChecked)
|
PrefManager.setVal(PrefName.SettingsPreferDub, isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
binding.settingsPinnedMangaSources.setOnClickListener {
|
|
||||||
val mangaSourcesWithoutDownloadsSource =
|
|
||||||
MangaSources.list.filter { it.name != "Downloaded" }
|
|
||||||
val names = mangaSourcesWithoutDownloadsSource.map { it.name }
|
|
||||||
val pinnedSourcesBoolean =
|
|
||||||
mangaSourcesWithoutDownloadsSource.map { it.name in MangaSources.pinnedMangaSources }
|
|
||||||
val pinnedSourcesOriginal: Set<String> = PrefManager.getVal(PrefName.PinnedMangaSources)
|
|
||||||
val pinnedSources = pinnedSourcesOriginal.toMutableSet()
|
|
||||||
val alertDialog = AlertDialog.Builder(this, R.style.MyPopup)
|
|
||||||
.setTitle("Pinned Manga Sources")
|
|
||||||
.setMultiChoiceItems(
|
|
||||||
names.toTypedArray(),
|
|
||||||
pinnedSourcesBoolean.toBooleanArray()
|
|
||||||
) { _, which, isChecked ->
|
|
||||||
if (isChecked) {
|
|
||||||
pinnedSources.add(MangaSources.names[which])
|
|
||||||
} else {
|
|
||||||
pinnedSources.remove(MangaSources.names[which])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setPositiveButton("OK") { dialog, _ ->
|
|
||||||
PrefManager.setVal(PrefName.PinnedMangaSources, pinnedSources)
|
|
||||||
MangaSources.pinnedMangaSources = pinnedSources
|
|
||||||
MangaSources.performReorderMangaSources()
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
.create()
|
|
||||||
alertDialog.show()
|
|
||||||
alertDialog.window?.setDimAmount(0.8f)
|
|
||||||
}
|
|
||||||
|
|
||||||
binding.settingsReader.setOnClickListener {
|
binding.settingsReader.setOnClickListener {
|
||||||
startActivity(Intent(this, ReaderSettingsActivity::class.java))
|
startActivity(Intent(this, ReaderSettingsActivity::class.java))
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,9 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
||||||
VerboseLogging(Pref(Location.General, Boolean::class, false)),
|
VerboseLogging(Pref(Location.General, Boolean::class, false)),
|
||||||
DohProvider(Pref(Location.General, Int::class, 0)),
|
DohProvider(Pref(Location.General, Int::class, 0)),
|
||||||
DefaultUserAgent(Pref(Location.General, String::class, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0")),
|
DefaultUserAgent(Pref(Location.General, String::class, "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0")),
|
||||||
PinnedAnimeSources(Pref(Location.General, Set::class, setOf<String>())),
|
AnimeSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
AnimeSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
AnimeSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
PinnedMangaSources(Pref(Location.General, Set::class, setOf<String>())),
|
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||||
MangaSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
MangaSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
||||||
|
|
||||||
//User Interface
|
//User Interface
|
||||||
|
|
|
@ -1101,37 +1101,6 @@
|
||||||
app:iconSize="24dp"
|
app:iconSize="24dp"
|
||||||
app:iconTint="?attr/colorPrimary" />
|
app:iconTint="?attr/colorPrimary" />
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_marginStart="-16dp"
|
|
||||||
android:layout_marginEnd="-16dp"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/settingsPinnedAnimeSources"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:layout_marginStart="-31dp"
|
|
||||||
android:layout_marginEnd="-31dp"
|
|
||||||
android:background="@drawable/ui_bg"
|
|
||||||
android:backgroundTint="?attr/colorSecondary"
|
|
||||||
android:backgroundTintMode="src_atop"
|
|
||||||
android:fontFamily="@font/poppins_bold"
|
|
||||||
android:insetTop="0dp"
|
|
||||||
android:insetBottom="0dp"
|
|
||||||
android:paddingStart="31dp"
|
|
||||||
android:paddingEnd="31dp"
|
|
||||||
android:text="@string/pinned_sources"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?attr/colorOnBackground"
|
|
||||||
app:cornerRadius="0dp"
|
|
||||||
app:icon="@drawable/ic_pin"
|
|
||||||
app:iconPadding="16dp"
|
|
||||||
app:iconSize="24dp"
|
|
||||||
app:iconTint="?attr/colorPrimary" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="1dp"
|
android:layout_height="1dp"
|
||||||
|
@ -1311,37 +1280,6 @@
|
||||||
android:layout_marginEnd="-16dp"
|
android:layout_marginEnd="-16dp"
|
||||||
android:background="?android:attr/listDivider" />
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/settingsPinnedMangaSources"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="64dp"
|
|
||||||
android:layout_marginStart="-31dp"
|
|
||||||
android:layout_marginEnd="-31dp"
|
|
||||||
android:background="@drawable/ui_bg"
|
|
||||||
android:backgroundTint="?attr/colorSecondary"
|
|
||||||
android:backgroundTintMode="src_atop"
|
|
||||||
android:fontFamily="@font/poppins_bold"
|
|
||||||
android:insetTop="0dp"
|
|
||||||
android:insetBottom="0dp"
|
|
||||||
android:paddingStart="31dp"
|
|
||||||
android:paddingEnd="31dp"
|
|
||||||
android:text="@string/pinned_sources"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textAllCaps="false"
|
|
||||||
android:textColor="?attr/colorOnBackground"
|
|
||||||
app:cornerRadius="0dp"
|
|
||||||
app:icon="@drawable/ic_pin"
|
|
||||||
app:iconPadding="16dp"
|
|
||||||
app:iconSize="24dp"
|
|
||||||
app:iconTint="?attr/colorPrimary" />
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:layout_marginStart="-16dp"
|
|
||||||
android:layout_marginEnd="-16dp"
|
|
||||||
android:background="?android:attr/listDivider" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/purgeMangaDownloads"
|
android:id="@+id/purgeMangaDownloads"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
android:paddingBottom="10dp">
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
@ -13,7 +14,7 @@
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
android:layout_gravity="center_vertical"
|
android:layout_gravity="center_vertical"
|
||||||
android:src="@drawable/ic_pin"
|
android:src="@drawable/ic_round_filter_24"
|
||||||
android:layout_marginEnd="3dp" />
|
android:layout_marginEnd="3dp" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue