Migrate to LongSet in selection controller

master
Koitharu 2 years ago
parent 6d07c335de
commit 92c8a13f96
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -95,7 +95,7 @@ dependencies {
implementation 'androidx.activity:activity-ktx:1.9.0' implementation 'androidx.activity:activity-ktx:1.9.0'
implementation 'androidx.fragment:fragment-ktx:1.8.1' implementation 'androidx.fragment:fragment-ktx:1.8.1'
implementation 'androidx.transition:transition-ktx:1.5.0' implementation 'androidx.transition:transition-ktx:1.5.0'
implementation 'androidx.collection:collection-ktx:1.4.0' implementation 'androidx.collection:collection-ktx:1.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3'
implementation 'androidx.lifecycle:lifecycle-service:2.8.3' implementation 'androidx.lifecycle:lifecycle-service:2.8.3'
implementation 'androidx.lifecycle:lifecycle-process:2.8.3' implementation 'androidx.lifecycle:lifecycle-process:2.8.3'

@ -1,11 +1,11 @@
package org.koitharu.kotatsu.core.ui.list package org.koitharu.kotatsu.core.ui.list
import android.app.Notification.Action
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.collection.LongSet
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
@ -14,6 +14,8 @@ import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryOwner import androidx.savedstate.SavedStateRegistryOwner
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
import org.koitharu.kotatsu.core.util.ext.toLongArray
import org.koitharu.kotatsu.core.util.ext.toSet
import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.EmptyCoroutineContext
private const val KEY_SELECTION = "selection" private const val KEY_SELECTION = "selection"
@ -35,11 +37,9 @@ class ListSelectionController(
registryOwner.lifecycle.addObserver(StateEventObserver()) registryOwner.lifecycle.addObserver(StateEventObserver())
} }
fun snapshot(): Set<Long> { fun snapshot(): Set<Long> = peekCheckedIds().toSet()
return peekCheckedIds().toSet()
}
fun peekCheckedIds(): Set<Long> { fun peekCheckedIds(): LongSet {
return decoration.checkedItemsIds return decoration.checkedItemsIds
} }

@ -4,6 +4,8 @@ import android.graphics.Canvas
import android.graphics.Rect import android.graphics.Rect
import android.graphics.RectF import android.graphics.RectF
import android.view.View import android.view.View
import androidx.collection.LongSet
import androidx.collection.MutableLongSet
import androidx.core.view.children import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.NO_ID import androidx.recyclerview.widget.RecyclerView.NO_ID
@ -12,7 +14,7 @@ abstract class AbstractSelectionItemDecoration : RecyclerView.ItemDecoration() {
private val bounds = Rect() private val bounds = Rect()
private val boundsF = RectF() private val boundsF = RectF()
protected val selection = HashSet<Long>() // TODO MutableLongSet protected val selection = MutableLongSet()
protected var hasBackground: Boolean = true protected var hasBackground: Boolean = true
protected var hasForeground: Boolean = false protected var hasForeground: Boolean = false
@ -21,7 +23,7 @@ abstract class AbstractSelectionItemDecoration : RecyclerView.ItemDecoration() {
val checkedItemsCount: Int val checkedItemsCount: Int
get() = selection.size get() = selection.size
val checkedItemsIds: Set<Long> val checkedItemsIds: LongSet
get() = selection get() = selection
fun toggleItemChecked(id: Long) { fun toggleItemChecked(id: Long) {
@ -39,7 +41,9 @@ abstract class AbstractSelectionItemDecoration : RecyclerView.ItemDecoration() {
} }
fun checkAll(ids: Collection<Long>) { fun checkAll(ids: Collection<Long>) {
selection.addAll(ids) for (id in ids) {
selection.add(id)
}
} }
fun clearSelection() { fun clearSelection() {

@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.util.ext
import androidx.collection.ArrayMap import androidx.collection.ArrayMap
import androidx.collection.ArraySet import androidx.collection.ArraySet
import androidx.collection.LongSet
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import java.util.Collections import java.util.Collections
import java.util.EnumSet import java.util.EnumSet
@ -77,3 +78,16 @@ inline fun <T, reified R> Collection<T>.mapToArray(transform: (T) -> R): Array<R
forEachIndexed { index, t -> result[index] = transform(t) } forEachIndexed { index, t -> result[index] = transform(t) }
return result as Array<R> return result as Array<R>
} }
fun LongSet.toLongArray(): LongArray {
val result = LongArray(size)
var i = 0
forEach { result[i++] = it }
return result
}
fun LongSet.toSet(): Set<Long> = toCollection(ArraySet<Long>(size))
fun <R : MutableCollection<Long>> LongSet.toCollection(out: R): R = out.also { result ->
forEach(result::add)
}

@ -32,6 +32,8 @@ import org.koitharu.kotatsu.core.util.ext.findAppCompatDelegate
import org.koitharu.kotatsu.core.util.ext.findParentCallback import org.koitharu.kotatsu.core.util.ext.findParentCallback
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.toCollection
import org.koitharu.kotatsu.core.util.ext.toSet
import org.koitharu.kotatsu.databinding.FragmentChaptersBinding import org.koitharu.kotatsu.databinding.FragmentChaptersBinding
import org.koitharu.kotatsu.details.ui.DetailsViewModel import org.koitharu.kotatsu.details.ui.DetailsViewModel
import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter import org.koitharu.kotatsu.details.ui.adapter.ChaptersAdapter
@ -137,10 +139,10 @@ class ChaptersFragment :
val ids = selectionController?.peekCheckedIds() val ids = selectionController?.peekCheckedIds()
val manga = viewModel.manga.value val manga = viewModel.manga.value
when { when {
ids.isNullOrEmpty() || manga == null -> Unit ids == null || ids.isEmpty() || manga == null -> Unit
ids.size == manga.chapters?.size -> viewModel.deleteLocal() ids.size == manga.chapters?.size -> viewModel.deleteLocal()
else -> { else -> {
LocalChaptersRemoveService.start(requireContext(), manga, ids) LocalChaptersRemoveService.start(requireContext(), manga, ids.toSet())
Snackbar.make( Snackbar.make(
requireViewBinding().recyclerViewChapters, requireViewBinding().recyclerViewChapters,
R.string.chapters_will_removed_background, R.string.chapters_will_removed_background,
@ -154,7 +156,7 @@ class ChaptersFragment :
R.id.action_select_range -> { R.id.action_select_range -> {
val items = chaptersAdapter?.items ?: return false val items = chaptersAdapter?.items ?: return false
val ids = HashSet(controller.peekCheckedIds()) val ids = controller.peekCheckedIds().toCollection(HashSet())
val buffer = HashSet<Long>() val buffer = HashSet<Long>()
var isAdding = false var isAdding = false
for (x in items) { for (x in items) {
@ -188,8 +190,12 @@ class ChaptersFragment :
} }
R.id.action_mark_current -> { R.id.action_mark_current -> {
val id = controller.peekCheckedIds().singleOrNull() ?: return false val ids = controller.peekCheckedIds()
viewModel.markChapterAsCurrent(id) if (ids.size == 1) {
viewModel.markChapterAsCurrent(ids.first())
} else {
return false
}
mode.finish() mode.finish()
true true
} }

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.download.ui.list package org.koitharu.kotatsu.download.ui.list
import androidx.collection.ArrayMap import androidx.collection.ArrayMap
import androidx.collection.LongSet
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import androidx.collection.getOrElse import androidx.collection.getOrElse
import androidx.collection.set import androidx.collection.set
@ -182,7 +183,7 @@ class DownloadsViewModel @Inject constructor(
} }
} }
fun snapshot(ids: Set<Long>): Collection<DownloadItemModel> { fun snapshot(ids: LongSet): Collection<DownloadItemModel> {
return works.value?.filterTo(ArrayList(ids.size)) { x -> x.id.mostSignificantBits in ids }.orEmpty() return works.value?.filterTo(ArrayList(ids.size)) { x -> x.id.mostSignificantBits in ids }.orEmpty()
} }

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.explore.ui package org.koitharu.kotatsu.explore.ui
import androidx.collection.LongSet
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -126,7 +127,7 @@ class ExploreViewModel @Inject constructor(
settings.closeTip(TIP_SUGGESTIONS) settings.closeTip(TIP_SUGGESTIONS)
} }
fun sourcesSnapshot(ids: Set<Long>): List<MangaSourceInfo> { fun sourcesSnapshot(ids: LongSet): List<MangaSourceInfo> {
return content.value.mapNotNull { return content.value.mapNotNull {
(it as? MangaSourceItem)?.takeIf { x -> x.id in ids }?.source (it as? MangaSourceItem)?.takeIf { x -> x.id in ids }?.source
} }

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.favourites.ui.categories package org.koitharu.kotatsu.favourites.ui.categories
import androidx.collection.LongSet
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -76,7 +77,7 @@ class FavouritesCategoriesViewModel @Inject constructor(
} }
} }
fun getCategories(ids: Set<Long>): ArrayList<FavouriteCategory> { fun getCategories(ids: LongSet): ArrayList<FavouriteCategory> {
val items = content.requireValue() val items = content.requireValue()
return items.mapNotNullTo(ArrayList(ids.size)) { item -> return items.mapNotNullTo(ArrayList(ids.size)) { item ->
(item as? CategoryListModel)?.category?.takeIf { it.id in ids } (item as? CategoryListModel)?.category?.takeIf { it.id in ids }

@ -14,7 +14,11 @@ import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblerManga
class ScrobblerMangaSelectionDecoration(context: Context) : MangaSelectionDecoration(context) { class ScrobblerMangaSelectionDecoration(context: Context) : MangaSelectionDecoration(context) {
var checkedItemId: Long var checkedItemId: Long
get() = selection.singleOrNull() ?: NO_ID get() = if (selection.size == 1) {
selection.first()
} else {
NO_ID
}
set(value) { set(value) {
clearSelection() clearSelection()
if (value != NO_ID) { if (value != NO_ID) {

@ -1,6 +1,7 @@
package org.koitharu.kotatsu.search.ui.multi package org.koitharu.kotatsu.search.ui.multi
import androidx.annotation.CheckResult import androidx.annotation.CheckResult
import androidx.collection.LongSet
import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -81,7 +82,7 @@ class MultiSearchViewModel @Inject constructor(
} }
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState)) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, listOf(LoadingState))
fun getItems(ids: Set<Long>): Set<Manga> { fun getItems(ids: LongSet): Set<Manga> {
val snapshot = listData.value ?: return emptySet() val snapshot = listData.value ?: return emptySet()
val result = HashSet<Manga>(ids.size) val result = HashSet<Manga>(ids.size)
snapshot.forEach { x -> snapshot.forEach { x ->

Loading…
Cancel
Save