mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	Add feature to clear database manga by source (#6241)
* Implement feature to selectively clear manga from database based on it's source * Code cleanup and refactoring
This commit is contained in:
		@@ -0,0 +1,3 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.models
 | 
			
		||||
 | 
			
		||||
data class SourceIdMangaCount(val source: Long, val count: Int)
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.queries
 | 
			
		||||
 | 
			
		||||
import com.pushtorefresh.storio.Queries
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.get.PreparedGetListOfObjects
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.DeleteQuery
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.queries.Query
 | 
			
		||||
@@ -7,6 +8,7 @@ import com.pushtorefresh.storio.sqlite.queries.RawQuery
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DbProvider
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.Manga
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.SourceIdMangaCount
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
 | 
			
		||||
@@ -14,6 +16,7 @@ import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaNextUpdatedPutResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.SourceIdMangaCountGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
 | 
			
		||||
@@ -70,6 +73,17 @@ interface MangaQueries : DbProvider {
 | 
			
		||||
        )
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun getSourceIdsWithNonLibraryManga() = db.get()
 | 
			
		||||
        .listOfObjects(SourceIdMangaCount::class.java)
 | 
			
		||||
        .withQuery(
 | 
			
		||||
            RawQuery.builder()
 | 
			
		||||
                .query(getSourceIdsWithNonLibraryMangaQuery())
 | 
			
		||||
                .observesTables(MangaTable.TABLE)
 | 
			
		||||
                .build()
 | 
			
		||||
        )
 | 
			
		||||
        .withGetResolver(SourceIdMangaCountGetResolver.INSTANCE)
 | 
			
		||||
        .prepare()
 | 
			
		||||
 | 
			
		||||
    fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
 | 
			
		||||
 | 
			
		||||
    fun insertMangas(mangas: List<Manga>) = db.put().objects(mangas).prepare()
 | 
			
		||||
@@ -123,12 +137,12 @@ interface MangaQueries : DbProvider {
 | 
			
		||||
 | 
			
		||||
    fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
 | 
			
		||||
 | 
			
		||||
    fun deleteMangasNotInLibrary() = db.delete()
 | 
			
		||||
    fun deleteMangasNotInLibraryBySourceIds(sourceIds: List<Long>) = db.delete()
 | 
			
		||||
        .byQuery(
 | 
			
		||||
            DeleteQuery.builder()
 | 
			
		||||
                .table(MangaTable.TABLE)
 | 
			
		||||
                .where("${MangaTable.COL_FAVORITE} = ?")
 | 
			
		||||
                .whereArgs(0)
 | 
			
		||||
                .where("${MangaTable.COL_FAVORITE} = ? AND ${MangaTable.COL_SOURCE} IN (${Queries.placeholders(sourceIds.size)})")
 | 
			
		||||
                .whereArgs(0, *sourceIds.toTypedArray())
 | 
			
		||||
                .build()
 | 
			
		||||
        )
 | 
			
		||||
        .prepare()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.queries
 | 
			
		||||
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.resolvers.SourceIdMangaCountGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.HistoryTable as History
 | 
			
		||||
@@ -142,3 +143,14 @@ fun getCategoriesForMangaQuery() =
 | 
			
		||||
    ${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID}
 | 
			
		||||
    WHERE ${MangaCategory.COL_MANGA_ID} = ?
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
/** Query to get the list of sources in the database that have
 | 
			
		||||
 * non-library manga, and how many
 | 
			
		||||
 */
 | 
			
		||||
fun getSourceIdsWithNonLibraryMangaQuery() =
 | 
			
		||||
    """
 | 
			
		||||
    SELECT ${Manga.COL_SOURCE}, COUNT(*) as ${SourceIdMangaCountGetResolver.COL_COUNT}
 | 
			
		||||
    FROM ${Manga.TABLE}
 | 
			
		||||
    WHERE ${Manga.COL_FAVORITE} = 0
 | 
			
		||||
    GROUP BY ${Manga.COL_SOURCE}
 | 
			
		||||
    """
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
package eu.kanade.tachiyomi.data.database.resolvers
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.database.Cursor
 | 
			
		||||
import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.SourceIdMangaCount
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
 | 
			
		||||
 | 
			
		||||
class SourceIdMangaCountGetResolver : DefaultGetResolver<SourceIdMangaCount>() {
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val INSTANCE = SourceIdMangaCountGetResolver()
 | 
			
		||||
        const val COL_COUNT = "manga_count"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("Range")
 | 
			
		||||
    override fun mapFromCursor(cursor: Cursor): SourceIdMangaCount {
 | 
			
		||||
        val sourceID = cursor.getLong(cursor.getColumnIndex(MangaTable.COL_SOURCE))
 | 
			
		||||
        val count = cursor.getInt(cursor.getColumnIndex(COL_COUNT))
 | 
			
		||||
 | 
			
		||||
        return SourceIdMangaCount(sourceID, count)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,10 +1,8 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.app.Dialog
 | 
			
		||||
import android.content.ActivityNotFoundException
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.provider.Settings
 | 
			
		||||
import androidx.core.net.toUri
 | 
			
		||||
import androidx.preference.PreferenceScreen
 | 
			
		||||
@@ -20,8 +18,9 @@ import eu.kanade.tachiyomi.network.NetworkHelper
 | 
			
		||||
import eu.kanade.tachiyomi.network.PREF_DOH_ADGUARD
 | 
			
		||||
import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
 | 
			
		||||
import eu.kanade.tachiyomi.network.PREF_DOH_GOOGLE
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.openInBrowser
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
 | 
			
		||||
import eu.kanade.tachiyomi.ui.setting.database.ClearDatabaseController
 | 
			
		||||
import eu.kanade.tachiyomi.util.CrashLogUtil
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.launchIO
 | 
			
		||||
import eu.kanade.tachiyomi.util.lang.withUIContext
 | 
			
		||||
@@ -143,9 +142,7 @@ class SettingsAdvancedController : SettingsController() {
 | 
			
		||||
                summaryRes = R.string.pref_clear_database_summary
 | 
			
		||||
 | 
			
		||||
                onClick {
 | 
			
		||||
                    val ctrl = ClearDatabaseDialogController()
 | 
			
		||||
                    ctrl.targetController = this@SettingsAdvancedController
 | 
			
		||||
                    ctrl.showDialog(router)
 | 
			
		||||
                    router.pushController(ClearDatabaseController().withFadeTransaction())
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -278,24 +275,6 @@ class SettingsAdvancedController : SettingsController() {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ClearDatabaseDialogController : DialogController() {
 | 
			
		||||
        override fun onCreateDialog(savedViewState: Bundle?): Dialog {
 | 
			
		||||
            return MaterialAlertDialogBuilder(activity!!)
 | 
			
		||||
                .setMessage(R.string.clear_database_confirmation)
 | 
			
		||||
                .setPositiveButton(android.R.string.ok) { _, _ ->
 | 
			
		||||
                    (targetController as? SettingsAdvancedController)?.clearDatabase()
 | 
			
		||||
                }
 | 
			
		||||
                .setNegativeButton(android.R.string.cancel, null)
 | 
			
		||||
                .create()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun clearDatabase() {
 | 
			
		||||
        db.deleteMangasNotInLibrary().executeAsBlocking()
 | 
			
		||||
        db.deleteHistoryNoLastRead().executeAsBlocking()
 | 
			
		||||
        activity?.toast(R.string.clear_database_completed)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
private const val CLEAR_CACHE_KEY = "pref_clear_cache_key"
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,172 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.database
 | 
			
		||||
 | 
			
		||||
import android.annotation.SuppressLint
 | 
			
		||||
import android.app.Dialog
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.Menu
 | 
			
		||||
import android.view.MenuInflater
 | 
			
		||||
import android.view.MenuItem
 | 
			
		||||
import android.view.View
 | 
			
		||||
import androidx.core.view.forEach
 | 
			
		||||
import androidx.core.view.get
 | 
			
		||||
import androidx.core.view.isVisible
 | 
			
		||||
import androidx.recyclerview.widget.LinearLayoutManager
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
 | 
			
		||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
 | 
			
		||||
import dev.chrisbanes.insetter.applyInsetter
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.Payload
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.ClearDatabaseControllerBinding
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.FabController
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
 | 
			
		||||
import eu.kanade.tachiyomi.util.system.toast
 | 
			
		||||
 | 
			
		||||
class ClearDatabaseController :
 | 
			
		||||
    NucleusController<ClearDatabaseControllerBinding, ClearDatabasePresenter>(),
 | 
			
		||||
    FlexibleAdapter.OnItemClickListener,
 | 
			
		||||
    FlexibleAdapter.OnUpdateListener,
 | 
			
		||||
    FabController {
 | 
			
		||||
 | 
			
		||||
    private var recycler: RecyclerView? = null
 | 
			
		||||
    private var adapter: FlexibleAdapter<ClearDatabaseSourceItem>? = null
 | 
			
		||||
 | 
			
		||||
    private var menu: Menu? = null
 | 
			
		||||
 | 
			
		||||
    private var actionFab: ExtendedFloatingActionButton? = null
 | 
			
		||||
    private var actionFabScrollListener: RecyclerView.OnScrollListener? = null
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        setHasOptionsMenu(true)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createBinding(inflater: LayoutInflater): ClearDatabaseControllerBinding {
 | 
			
		||||
        return ClearDatabaseControllerBinding.inflate(inflater)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createPresenter(): ClearDatabasePresenter {
 | 
			
		||||
        return ClearDatabasePresenter()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getTitle(): String? {
 | 
			
		||||
        return activity?.getString(R.string.pref_clear_database)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View) {
 | 
			
		||||
        super.onViewCreated(view)
 | 
			
		||||
 | 
			
		||||
        binding.recycler.applyInsetter {
 | 
			
		||||
            type(navigationBars = true) {
 | 
			
		||||
                padding()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        adapter = FlexibleAdapter<ClearDatabaseSourceItem>(null, this, true)
 | 
			
		||||
        binding.recycler.adapter = adapter
 | 
			
		||||
        binding.recycler.layoutManager = LinearLayoutManager(activity)
 | 
			
		||||
        binding.recycler.setHasFixedSize(true)
 | 
			
		||||
        adapter?.fastScroller = binding.fastScroller
 | 
			
		||||
        recycler = binding.recycler
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onDestroyView(view: View) {
 | 
			
		||||
        adapter = null
 | 
			
		||||
        super.onDestroyView(view)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
 | 
			
		||||
        inflater.inflate(R.menu.generic_selection, menu)
 | 
			
		||||
        this.menu = menu
 | 
			
		||||
        menu.forEach { menuItem -> menuItem.isVisible = (adapter?.itemCount ?: 0) > 0 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
 | 
			
		||||
        val adapter = adapter ?: return false
 | 
			
		||||
        when (item.itemId) {
 | 
			
		||||
            R.id.action_select_all -> adapter.selectAll()
 | 
			
		||||
            R.id.action_select_inverse -> {
 | 
			
		||||
                val currentSelection = adapter.selectedPositionsAsSet
 | 
			
		||||
                val invertedSelection = (0..adapter.itemCount)
 | 
			
		||||
                    .filterNot { currentSelection.contains(it) }
 | 
			
		||||
                currentSelection.clear()
 | 
			
		||||
                currentSelection.addAll(invertedSelection)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        updateFab()
 | 
			
		||||
        adapter.notifyItemRangeChanged(0, adapter.itemCount, Payload.SELECTION)
 | 
			
		||||
        return super.onOptionsItemSelected(item)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onUpdateEmptyView(size: Int) {
 | 
			
		||||
        if (size > 0) {
 | 
			
		||||
            binding.emptyView.hide()
 | 
			
		||||
        } else {
 | 
			
		||||
            binding.emptyView.show(activity!!.getString(R.string.database_clean))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        menu?.forEach { menuItem -> menuItem.isVisible = size > 0 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onItemClick(view: View?, position: Int): Boolean {
 | 
			
		||||
        val adapter = adapter ?: return false
 | 
			
		||||
        adapter.toggleSelection(position)
 | 
			
		||||
        adapter.notifyItemChanged(position, Payload.SELECTION)
 | 
			
		||||
        updateFab()
 | 
			
		||||
        return true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun setItems(items: List<ClearDatabaseSourceItem>) {
 | 
			
		||||
        adapter?.updateDataSet(items)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun configureFab(fab: ExtendedFloatingActionButton) {
 | 
			
		||||
        fab.setIconResource(R.drawable.ic_delete_24dp)
 | 
			
		||||
        fab.setText(R.string.action_delete)
 | 
			
		||||
        fab.isVisible = false
 | 
			
		||||
        fab.setOnClickListener {
 | 
			
		||||
            val ctrl = ClearDatabaseSourcesDialog()
 | 
			
		||||
            ctrl.targetController = this
 | 
			
		||||
            ctrl.showDialog(router)
 | 
			
		||||
        }
 | 
			
		||||
        actionFab = fab
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun updateFab() {
 | 
			
		||||
        val adapter = adapter ?: return
 | 
			
		||||
        actionFab?.isVisible = adapter.selectedItemCount > 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun cleanupFab(fab: ExtendedFloatingActionButton) {
 | 
			
		||||
        actionFab?.setOnClickListener(null)
 | 
			
		||||
        actionFabScrollListener?.let { recycler?.removeOnScrollListener(it) }
 | 
			
		||||
        actionFab = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class ClearDatabaseSourcesDialog : DialogController() {
 | 
			
		||||
        override fun onCreateDialog(savedViewState: Bundle?): Dialog {
 | 
			
		||||
            return MaterialAlertDialogBuilder(activity!!)
 | 
			
		||||
                .setMessage(R.string.clear_database_confirmation)
 | 
			
		||||
                .setPositiveButton(android.R.string.ok) { _, _ ->
 | 
			
		||||
                    (targetController as? ClearDatabaseController)?.clearDatabaseForSelectedSources()
 | 
			
		||||
                }
 | 
			
		||||
                .setNegativeButton(android.R.string.cancel, null)
 | 
			
		||||
                .create()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @SuppressLint("NotifyDataSetChanged")
 | 
			
		||||
    private fun clearDatabaseForSelectedSources() {
 | 
			
		||||
        val adapter = adapter ?: return
 | 
			
		||||
        val selectedSourceIds = adapter.selectedPositions.mapNotNull { position ->
 | 
			
		||||
            adapter.getItem(position)?.source?.id
 | 
			
		||||
        }
 | 
			
		||||
        presenter.clearDatabaseForSourceIds(selectedSourceIds)
 | 
			
		||||
        actionFab!!.isVisible = false
 | 
			
		||||
        adapter.clearSelection()
 | 
			
		||||
        adapter.notifyDataSetChanged()
 | 
			
		||||
        activity?.toast(R.string.clear_database_completed)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.database
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
 | 
			
		||||
import eu.kanade.tachiyomi.source.SourceManager
 | 
			
		||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 | 
			
		||||
import rx.Observable
 | 
			
		||||
import rx.schedulers.Schedulers
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
 | 
			
		||||
class ClearDatabasePresenter : BasePresenter<ClearDatabaseController>() {
 | 
			
		||||
 | 
			
		||||
    private val db = Injekt.get<DatabaseHelper>()
 | 
			
		||||
 | 
			
		||||
    private val sourceManager = Injekt.get<SourceManager>()
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedState)
 | 
			
		||||
        getDatabaseSourcesObservable()
 | 
			
		||||
            .subscribeOn(Schedulers.io())
 | 
			
		||||
            .subscribeLatestCache(ClearDatabaseController::setItems)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun clearDatabaseForSourceIds(sources: List<Long>) {
 | 
			
		||||
        db.deleteMangasNotInLibraryBySourceIds(sources).executeAsBlocking()
 | 
			
		||||
        db.deleteHistoryNoLastRead().executeAsBlocking()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getDatabaseSourcesObservable(): Observable<List<ClearDatabaseSourceItem>> {
 | 
			
		||||
        return db.getSourceIdsWithNonLibraryManga().asRxObservable()
 | 
			
		||||
            .map { sourceCounts ->
 | 
			
		||||
                sourceCounts.map {
 | 
			
		||||
                    val sourceObj = sourceManager.getOrStub(it.source)
 | 
			
		||||
                    ClearDatabaseSourceItem(sourceObj, it.count)
 | 
			
		||||
                }.sortedBy { it.source.name }
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.setting.database
 | 
			
		||||
 | 
			
		||||
import android.view.View
 | 
			
		||||
import androidx.recyclerview.widget.RecyclerView
 | 
			
		||||
import eu.davidea.flexibleadapter.FlexibleAdapter
 | 
			
		||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
 | 
			
		||||
import eu.davidea.flexibleadapter.items.IFlexible
 | 
			
		||||
import eu.davidea.viewholders.FlexibleViewHolder
 | 
			
		||||
import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.databinding.ClearDatabaseSourceItemBinding
 | 
			
		||||
import eu.kanade.tachiyomi.source.LocalSource
 | 
			
		||||
import eu.kanade.tachiyomi.source.Source
 | 
			
		||||
import eu.kanade.tachiyomi.source.SourceManager
 | 
			
		||||
import eu.kanade.tachiyomi.source.icon
 | 
			
		||||
 | 
			
		||||
data class ClearDatabaseSourceItem(val source: Source, private val mangaCount: Int) : AbstractFlexibleItem<ClearDatabaseSourceItem.Holder>() {
 | 
			
		||||
 | 
			
		||||
    override fun getLayoutRes(): Int {
 | 
			
		||||
        return R.layout.clear_database_source_item
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
 | 
			
		||||
        return Holder(view, adapter)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?, holder: Holder?, position: Int, payloads: MutableList<Any>?) {
 | 
			
		||||
        if (payloads.isNullOrEmpty()) {
 | 
			
		||||
            holder?.bind(source, mangaCount)
 | 
			
		||||
        } else {
 | 
			
		||||
            holder?.updateCheckbox()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
 | 
			
		||||
 | 
			
		||||
        private val binding = ClearDatabaseSourceItemBinding.bind(view)
 | 
			
		||||
 | 
			
		||||
        fun bind(source: Source, count: Int) {
 | 
			
		||||
            binding.title.text = source.toString()
 | 
			
		||||
            binding.description.text = itemView.context.getString(R.string.clear_database_source_item_count, count)
 | 
			
		||||
 | 
			
		||||
            itemView.post {
 | 
			
		||||
                when {
 | 
			
		||||
                    source.id == LocalSource.ID -> binding.thumbnail.setImageResource(R.mipmap.ic_local_source)
 | 
			
		||||
                    source is SourceManager.StubSource -> binding.thumbnail.setImageDrawable(null)
 | 
			
		||||
                    source.icon() != null -> binding.thumbnail.setImageDrawable(source.icon())
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        fun updateCheckbox() {
 | 
			
		||||
            binding.checkbox.isChecked = (bindingAdapter as FlexibleAdapter<*>).isSelected(bindingAdapterPosition)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user