diff --git a/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt index 87db873257..fa65314eb3 100644 --- a/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/source/SourceRepositoryImpl.kt @@ -2,12 +2,12 @@ package eu.kanade.data.source import eu.kanade.data.DatabaseHandler import eu.kanade.domain.source.model.Source +import eu.kanade.domain.source.model.SourceWithCount import eu.kanade.domain.source.repository.SourceRepository import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.SourceManager import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map -import eu.kanade.tachiyomi.source.Source as LoadedSource class SourceRepositoryImpl( private val sourceManager: SourceManager, @@ -40,12 +40,12 @@ class SourceRepositoryImpl( } } - override fun getSourcesWithNonLibraryManga(): Flow>> { + override fun getSourcesWithNonLibraryManga(): Flow> { val sourceIdWithNonLibraryManga = handler.subscribeToList { mangasQueries.getSourceIdsWithNonLibraryManga() } return sourceIdWithNonLibraryManga.map { sourceId -> sourceId.map { (sourceId, count) -> val source = sourceManager.getOrStub(sourceId) - source to count + SourceWithCount(sourceMapper(source), count) } } } diff --git a/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithNonLibraryManga.kt b/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithNonLibraryManga.kt index 5bcf634432..593f70ba7d 100644 --- a/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithNonLibraryManga.kt +++ b/app/src/main/java/eu/kanade/domain/source/interactor/GetSourcesWithNonLibraryManga.kt @@ -1,14 +1,14 @@ package eu.kanade.domain.source.interactor +import eu.kanade.domain.source.model.SourceWithCount import eu.kanade.domain.source.repository.SourceRepository -import eu.kanade.tachiyomi.source.Source import kotlinx.coroutines.flow.Flow class GetSourcesWithNonLibraryManga( private val repository: SourceRepository, ) { - fun subscribe(): Flow>> { + fun subscribe(): Flow> { return repository.getSourcesWithNonLibraryManga() } } diff --git a/app/src/main/java/eu/kanade/domain/source/model/SourceWithCount.kt b/app/src/main/java/eu/kanade/domain/source/model/SourceWithCount.kt new file mode 100644 index 0000000000..67a224ce8d --- /dev/null +++ b/app/src/main/java/eu/kanade/domain/source/model/SourceWithCount.kt @@ -0,0 +1,13 @@ +package eu.kanade.domain.source.model + +data class SourceWithCount( + val source: Source, + val count: Long, +) { + + val id: Long + get() = source.id + + val name: String + get() = source.name +} diff --git a/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt b/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt index 00590ca9b2..daece063d0 100644 --- a/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt +++ b/app/src/main/java/eu/kanade/domain/source/repository/SourceRepository.kt @@ -1,8 +1,8 @@ package eu.kanade.domain.source.repository import eu.kanade.domain.source.model.Source +import eu.kanade.domain.source.model.SourceWithCount import kotlinx.coroutines.flow.Flow -import eu.kanade.tachiyomi.source.Source as LoadedSource interface SourceRepository { @@ -12,5 +12,5 @@ interface SourceRepository { fun getSourcesWithFavoriteCount(): Flow>> - fun getSourcesWithNonLibraryManga(): Flow>> + fun getSourcesWithNonLibraryManga(): Flow> } diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseScreen.kt new file mode 100644 index 0000000000..0f5882bcec --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseScreen.kt @@ -0,0 +1,57 @@ +package eu.kanade.presentation.more.settings.database + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import eu.kanade.presentation.components.Scaffold +import eu.kanade.presentation.more.settings.database.components.ClearDatabaseContent +import eu.kanade.presentation.more.settings.database.components.ClearDatabaseDeleteDialog +import eu.kanade.presentation.more.settings.database.components.ClearDatabaseFloatingActionButton +import eu.kanade.presentation.more.settings.database.components.ClearDatabaseToolbar +import eu.kanade.presentation.util.plus +import eu.kanade.tachiyomi.R +import eu.kanade.tachiyomi.ui.setting.database.ClearDatabasePresenter +import eu.kanade.tachiyomi.util.system.toast + +@Composable +fun ClearDatabaseScreen( + presenter: ClearDatabasePresenter, + navigateUp: () -> Unit, +) { + val context = LocalContext.current + Scaffold( + topBar = { + ClearDatabaseToolbar( + state = presenter, + navigateUp = navigateUp, + onClickSelectAll = { presenter.selectAll() }, + onClickInvertSelection = { presenter.invertSelection() }, + ) + }, + floatingActionButton = { + ClearDatabaseFloatingActionButton( + isVisible = presenter.selection.isNotEmpty(), + onClickDelete = { + presenter.dialog = ClearDatabasePresenter.Dialog.Delete(presenter.selection) + }, + ) + }, + ) { paddingValues -> + ClearDatabaseContent( + state = presenter, + contentPadding = paddingValues, + onClickSelection = { source -> + presenter.toggleSelection(source) + }, + ) + } + if (presenter.dialog is ClearDatabasePresenter.Dialog.Delete) { + ClearDatabaseDeleteDialog( + onDismissRequest = { presenter.dialog = null }, + onDelete = { + presenter.removeMangaBySourceId((presenter.dialog as ClearDatabasePresenter.Dialog.Delete).sourceIds) + presenter.clearSelection() + context.toast(R.string.clear_database_completed) + }, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt new file mode 100644 index 0000000000..34281eab82 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/ClearDatabaseState.kt @@ -0,0 +1,28 @@ +package eu.kanade.presentation.more.settings.database + +import androidx.compose.runtime.Stable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import eu.kanade.domain.source.model.SourceWithCount +import eu.kanade.tachiyomi.ui.setting.database.ClearDatabasePresenter + +@Stable +interface ClearDatabaseState { + val items: List + val selection: List + val isEmpty: Boolean + var dialog: ClearDatabasePresenter.Dialog? +} + +fun ClearDatabaseState(): ClearDatabaseState { + return ClearDatabaseStateImpl() +} + +class ClearDatabaseStateImpl : ClearDatabaseState { + override var items: List by mutableStateOf(emptyList()) + override var selection: List by mutableStateOf(emptyList()) + override val isEmpty: Boolean by derivedStateOf { items.isEmpty() } + override var dialog: ClearDatabasePresenter.Dialog? by mutableStateOf(null) +} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseContent.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseContent.kt new file mode 100644 index 0000000000..195f7bd1bc --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseContent.kt @@ -0,0 +1,41 @@ +package eu.kanade.presentation.more.settings.database.components + +import androidx.compose.animation.Crossfade +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.lazy.items +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import eu.kanade.domain.source.model.Source +import eu.kanade.presentation.components.EmptyScreen +import eu.kanade.presentation.components.FastScrollLazyColumn +import eu.kanade.presentation.more.settings.database.ClearDatabaseState +import eu.kanade.presentation.util.plus +import eu.kanade.tachiyomi.R + +@Composable +fun ClearDatabaseContent( + state: ClearDatabaseState, + contentPadding: PaddingValues, + onClickSelection: (Source) -> Unit, +) { + Crossfade(targetState = state.isEmpty.not()) { _state -> + when (_state) { + true -> FastScrollLazyColumn( + contentPadding = contentPadding + WindowInsets.navigationBars.asPaddingValues(), + ) { + items(state.items) { sourceWithCount -> + ClearDatabaseItem( + source = sourceWithCount.source, + count = sourceWithCount.count, + isSelected = state.selection.contains(sourceWithCount.id), + onClickSelect = { onClickSelection(sourceWithCount.source) }, + ) + } + } + false -> EmptyScreen(message = stringResource(id = R.string.database_clean)) + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseDialogs.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseDialogs.kt new file mode 100644 index 0000000000..926fa4baf0 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseDialogs.kt @@ -0,0 +1,31 @@ +package eu.kanade.presentation.more.settings.database.components + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import eu.kanade.presentation.components.TextButton +import eu.kanade.tachiyomi.R + +@Composable +fun ClearDatabaseDeleteDialog( + onDismissRequest: () -> Unit, + onDelete: () -> Unit, +) { + AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + TextButton(onClick = onDelete) { + Text(text = stringResource(id = android.R.string.ok)) + } + }, + dismissButton = { + TextButton(onClick = onDismissRequest) { + Text(text = stringResource(id = android.R.string.cancel)) + } + }, + text = { + Text(text = stringResource(id = R.string.clear_database_confirmation)) + }, + ) +} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseFloatingActionButton.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseFloatingActionButton.kt new file mode 100644 index 0000000000..fcbd385934 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseFloatingActionButton.kt @@ -0,0 +1,38 @@ +package eu.kanade.presentation.more.settings.database.components + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Delete +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import eu.kanade.presentation.components.ExtendedFloatingActionButton +import eu.kanade.tachiyomi.R + +@Composable +fun ClearDatabaseFloatingActionButton( + isVisible: Boolean, + onClickDelete: () -> Unit, +) { + AnimatedVisibility( + visible = isVisible, + enter = fadeIn(), + exit = fadeOut(), + ) { + ExtendedFloatingActionButton( + modifier = Modifier.navigationBarsPadding(), + text = { + Text(text = stringResource(id = R.string.action_delete)) + }, + icon = { + Icon(Icons.Outlined.Delete, contentDescription = "") + }, + onClick = onClickDelete, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseItem.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseItem.kt new file mode 100644 index 0000000000..084a9359f9 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseItem.kt @@ -0,0 +1,53 @@ +package eu.kanade.presentation.more.settings.database.components + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Checkbox +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import eu.kanade.domain.source.model.Source +import eu.kanade.presentation.browse.components.SourceIcon +import eu.kanade.presentation.util.selectedBackground +import eu.kanade.tachiyomi.R + +@Composable +fun ClearDatabaseItem( + source: Source, + count: Long, + isSelected: Boolean, + onClickSelect: () -> Unit, +) { + Row( + modifier = Modifier + .selectedBackground(isSelected) + .clickable(onClick = onClickSelect) + .padding(horizontal = 8.dp) + .height(56.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + SourceIcon(source = source) + Column( + modifier = Modifier + .padding(start = 8.dp) + .weight(1f), + ) { + Text( + text = source.nameWithLanguage, + style = MaterialTheme.typography.bodyMedium, + ) + Text(text = stringResource(id = R.string.clear_database_source_item_count, count)) + } + Checkbox( + checked = isSelected, + onCheckedChange = { onClickSelect() }, + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseToolbar.kt b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseToolbar.kt new file mode 100644 index 0000000000..207cea92de --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/more/settings/database/components/ClearDatabaseToolbar.kt @@ -0,0 +1,42 @@ +package eu.kanade.presentation.more.settings.database.components + +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.FlipToBack +import androidx.compose.material.icons.outlined.SelectAll +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import eu.kanade.presentation.components.AppBar +import eu.kanade.presentation.components.AppBarActions +import eu.kanade.presentation.more.settings.database.ClearDatabaseState +import eu.kanade.tachiyomi.R + +@Composable +fun ClearDatabaseToolbar( + state: ClearDatabaseState, + navigateUp: () -> Unit, + onClickSelectAll: () -> Unit, + onClickInvertSelection: () -> Unit, +) { + AppBar( + title = stringResource(id = R.string.pref_clear_database), + navigateUp = navigateUp, + actions = { + if (state.isEmpty.not()) { + AppBarActions( + actions = listOf( + AppBar.Action( + title = stringResource(id = R.string.action_select_all), + icon = Icons.Outlined.SelectAll, + onClick = onClickSelectAll, + ), + AppBar.Action( + title = stringResource(id = R.string.action_select_all), + icon = Icons.Outlined.FlipToBack, + onClick = onClickInvertSelection, + ), + ), + ) + } + }, + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt index a0992b95d7..7aff3fdecd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseController.kt @@ -1,171 +1,20 @@ 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.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 +import androidx.compose.runtime.Composable +import eu.kanade.presentation.more.settings.database.ClearDatabaseScreen +import eu.kanade.tachiyomi.ui.base.controller.FullComposeController -class ClearDatabaseController : - NucleusController(), - FlexibleAdapter.OnItemClickListener, - FlexibleAdapter.OnUpdateListener, - FabController { - - private var recycler: RecyclerView? = null - private var adapter: FlexibleAdapter? = null - - private var menu: Menu? = null - - private var actionFab: ExtendedFloatingActionButton? = null - - init { - setHasOptionsMenu(true) - } - - override fun createBinding(inflater: LayoutInflater): ClearDatabaseControllerBinding { - return ClearDatabaseControllerBinding.inflate(inflater) - } +class ClearDatabaseController : FullComposeController() { 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(null, this, true) - binding.recycler.adapter = adapter - binding.recycler.layoutManager = LinearLayoutManager(view.context) - 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 -> { - adapter.currentItems.forEachIndexed { index, _ -> - adapter.toggleSelection(index) - } - } - } - 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) { - adapter?.updateDataSet(items) - } - - override fun configureFab(fab: ExtendedFloatingActionButton) { - fab.setIconResource(R.drawable.ic_delete_24dp) - fab.setText(R.string.action_delete) - fab.hide() - fab.setOnClickListener { - val ctrl = ClearDatabaseSourcesDialog() - ctrl.targetController = this - ctrl.showDialog(router) - } - actionFab = fab - } - - private fun updateFab() { - val adapter = adapter ?: return - if (adapter.selectedItemCount > 0) { - actionFab?.show() - } else { - actionFab?.hide() - } - } - - override fun cleanupFab(fab: ExtendedFloatingActionButton) { - actionFab?.setOnClickListener(null) - 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) + @Composable + override fun ComposeContent() { + ClearDatabaseScreen( + presenter = presenter, + navigateUp = { router.popCurrentController() }, + ) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt index 0c9081ae49..27c9bda306 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabasePresenter.kt @@ -2,18 +2,21 @@ package eu.kanade.tachiyomi.ui.setting.database import android.os.Bundle import eu.kanade.domain.source.interactor.GetSourcesWithNonLibraryManga +import eu.kanade.domain.source.model.Source +import eu.kanade.presentation.more.settings.database.ClearDatabaseState +import eu.kanade.presentation.more.settings.database.ClearDatabaseStateImpl import eu.kanade.tachiyomi.Database import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.withUIContext import kotlinx.coroutines.flow.collectLatest import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get class ClearDatabasePresenter( + private val state: ClearDatabaseStateImpl = ClearDatabaseState() as ClearDatabaseStateImpl, private val database: Database = Injekt.get(), private val getSourcesWithNonLibraryManga: GetSourcesWithNonLibraryManga = Injekt.get(), -) : BasePresenter() { +) : BasePresenter(), ClearDatabaseState by state { override fun onCreate(savedState: Bundle?) { super.onCreate(savedState) @@ -21,17 +24,39 @@ class ClearDatabasePresenter( presenterScope.launchIO { getSourcesWithNonLibraryManga.subscribe() .collectLatest { list -> - val items = list - .map { (source, count) -> ClearDatabaseSourceItem(source, count) } - .sortedBy { it.source.name } - - withUIContext { view?.setItems(items) } + state.items = list.sortedBy { it.name } } } } - fun clearDatabaseForSourceIds(sources: List) { - database.mangasQueries.deleteMangasNotInLibraryBySourceIds(sources) + fun removeMangaBySourceId(sourceIds: List) { + database.mangasQueries.deleteMangasNotInLibraryBySourceIds(sourceIds) database.historyQueries.removeResettedHistory() } + + fun toggleSelection(source: Source) { + val mutableList = state.selection.toMutableList() + if (mutableList.contains(source.id)) { + mutableList.remove(source.id) + } else { + mutableList.add(source.id) + } + state.selection = mutableList + } + + fun clearSelection() { + state.selection = emptyList() + } + + fun selectAll() { + state.selection = state.items.map { it.id } + } + + fun invertSelection() { + state.selection = state.items.map { it.id }.filterNot { it in state.selection } + } + + sealed class Dialog { + data class Delete(val sourceIds: List) : Dialog() + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseSourceItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseSourceItem.kt deleted file mode 100644 index d06af12594..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/database/ClearDatabaseSourceItem.kt +++ /dev/null @@ -1,48 +0,0 @@ -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.icon - -data class ClearDatabaseSourceItem(val source: Source, private val mangaCount: Long) : AbstractFlexibleItem() { - - override fun getLayoutRes(): Int { - return R.layout.clear_database_source_item - } - - override fun createViewHolder(view: View, adapter: FlexibleAdapter>): Holder { - return Holder(view, adapter) - } - - override fun bindViewHolder(adapter: FlexibleAdapter>?, holder: Holder?, position: Int, payloads: MutableList?) { - holder?.bind(source, mangaCount) - } - - class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) { - - private val binding = ClearDatabaseSourceItemBinding.bind(view) - - fun bind(source: Source, count: Long) { - binding.title.text = source.toString() - binding.description.text = itemView.context.getString(R.string.clear_database_source_item_count, count) - - itemView.post { - when { - source.icon() != null && source.id != LocalSource.ID -> - binding.thumbnail.setImageDrawable(source.icon()) - else -> binding.thumbnail.setImageResource(R.mipmap.ic_local_source) - } - } - - binding.checkbox.isChecked = (bindingAdapter as FlexibleAdapter<*>).isSelected(bindingAdapterPosition) - } - } -} diff --git a/app/src/main/res/layout/clear_database_controller.xml b/app/src/main/res/layout/clear_database_controller.xml deleted file mode 100644 index 70027af456..0000000000 --- a/app/src/main/res/layout/clear_database_controller.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/clear_database_source_item.xml b/app/src/main/res/layout/clear_database_source_item.xml deleted file mode 100644 index 823668a53b..0000000000 --- a/app/src/main/res/layout/clear_database_source_item.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file