Various fixes
This commit is contained in:
@@ -65,6 +65,7 @@ abstract class BaseViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun <T> Flow<T>.withErrorHandling() = catch { error ->
|
protected fun <T> Flow<T>.withErrorHandling() = catch { error ->
|
||||||
|
error.printStackTraceDebug()
|
||||||
errorEvent.call(error)
|
errorEvent.call(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,3 +97,14 @@ fun LongSet.toSet(): Set<Long> = toCollection(ArraySet<Long>(size))
|
|||||||
fun <R : MutableCollection<Long>> LongSet.toCollection(out: R): R = out.also { result ->
|
fun <R : MutableCollection<Long>> LongSet.toCollection(out: R): R = out.also { result ->
|
||||||
forEach(result::add)
|
forEach(result::add)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T, R> Collection<T>.mapSortedByCount(isDescending: Boolean = true, mapper: (T) -> R): List<R> {
|
||||||
|
val grouped = groupBy(mapper).toList()
|
||||||
|
val sortSelector: (Pair<R, List<T>>) -> Int = { it.second.size }
|
||||||
|
val sorted = if (isDescending) {
|
||||||
|
grouped.sortedByDescending(sortSelector)
|
||||||
|
} else {
|
||||||
|
grouped.sortedBy(sortSelector)
|
||||||
|
}
|
||||||
|
return sorted.map { it.first }
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.flow.flatMapLatest
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import org.koitharu.kotatsu.BuildConfig
|
import org.koitharu.kotatsu.BuildConfig
|
||||||
@@ -50,14 +49,13 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
private val dao: MangaSourcesDao
|
private val dao: MangaSourcesDao
|
||||||
get() = db.getSourcesDao()
|
get() = db.getSourcesDao()
|
||||||
|
|
||||||
private val remoteSources = EnumSet.allOf(MangaParserSource::class.java).apply {
|
val allMangaSources: Set<MangaParserSource> = Collections.unmodifiableSet(
|
||||||
if (!BuildConfig.DEBUG) {
|
EnumSet.allOf(MangaParserSource::class.java).apply {
|
||||||
remove(MangaParserSource.DUMMY)
|
if (!BuildConfig.DEBUG) {
|
||||||
}
|
remove(MangaParserSource.DUMMY)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
val allMangaSources: Set<MangaParserSource>
|
)
|
||||||
get() = Collections.unmodifiableSet(remoteSources)
|
|
||||||
|
|
||||||
suspend fun getEnabledSources(): List<MangaSource> {
|
suspend fun getEnabledSources(): List<MangaSource> {
|
||||||
assimilateNewSources()
|
assimilateNewSources()
|
||||||
@@ -86,7 +84,7 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
|
|
||||||
suspend fun getDisabledSources(): Set<MangaSource> {
|
suspend fun getDisabledSources(): Set<MangaSource> {
|
||||||
assimilateNewSources()
|
assimilateNewSources()
|
||||||
val result = EnumSet.copyOf(remoteSources)
|
val result = EnumSet.copyOf(allMangaSources)
|
||||||
val enabled = dao.findAllEnabledNames()
|
val enabled = dao.findAllEnabledNames()
|
||||||
for (name in enabled) {
|
for (name in enabled) {
|
||||||
val source = name.toMangaSourceOrNull() ?: continue
|
val source = name.toMangaSourceOrNull() ?: continue
|
||||||
@@ -182,7 +180,7 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
val result = ArrayList<Pair<MangaSource, Boolean>>(entities.size)
|
val result = ArrayList<Pair<MangaSource, Boolean>>(entities.size)
|
||||||
for (entity in entities) {
|
for (entity in entities) {
|
||||||
val source = entity.source.toMangaSourceOrNull() ?: continue
|
val source = entity.source.toMangaSourceOrNull() ?: continue
|
||||||
if (source in remoteSources) {
|
if (source in allMangaSources) {
|
||||||
result.add(source to entity.isEnabled)
|
result.add(source to entity.isEnabled)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,7 +197,7 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
suspend fun setSourcesEnabledExclusive(sources: Set<MangaSource>) {
|
suspend fun setSourcesEnabledExclusive(sources: Set<MangaSource>) {
|
||||||
db.withTransaction {
|
db.withTransaction {
|
||||||
assimilateNewSources()
|
assimilateNewSources()
|
||||||
for (s in remoteSources) {
|
for (s in allMangaSources) {
|
||||||
dao.setEnabled(s.name, s in sources)
|
dao.setEnabled(s.name, s in sources)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +220,7 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
|
|
||||||
fun observeHasNewSources(): Flow<Boolean> = observeIsNsfwDisabled().map { skipNsfw ->
|
fun observeHasNewSources(): Flow<Boolean> = observeIsNsfwDisabled().map { skipNsfw ->
|
||||||
val sources = dao.findAllFromVersion(BuildConfig.VERSION_CODE).toSources(skipNsfw, null)
|
val sources = dao.findAllFromVersion(BuildConfig.VERSION_CODE).toSources(skipNsfw, null)
|
||||||
sources.isNotEmpty() && sources.size != remoteSources.size
|
sources.isNotEmpty() && sources.size != allMangaSources.size
|
||||||
}.onStart { assimilateNewSources() }
|
}.onStart { assimilateNewSources() }
|
||||||
|
|
||||||
fun observeHasNewSourcesForBadge(): Flow<Boolean> = combine(
|
fun observeHasNewSourcesForBadge(): Flow<Boolean> = combine(
|
||||||
@@ -295,7 +293,7 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
|
|
||||||
private suspend fun getNewSources(): MutableSet<out MangaSource> {
|
private suspend fun getNewSources(): MutableSet<out MangaSource> {
|
||||||
val entities = dao.findAll()
|
val entities = dao.findAll()
|
||||||
val result = EnumSet.copyOf(remoteSources)
|
val result = EnumSet.copyOf(allMangaSources)
|
||||||
for (e in entities) {
|
for (e in entities) {
|
||||||
result.remove(e.source.toMangaSourceOrNull() ?: continue)
|
result.remove(e.source.toMangaSourceOrNull() ?: continue)
|
||||||
}
|
}
|
||||||
@@ -361,7 +359,7 @@ class MangaSourcesRepository @Inject constructor(
|
|||||||
if (skipNsfwSources && source.isNsfw()) {
|
if (skipNsfwSources && source.isNsfw()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (source in remoteSources) {
|
if (source in allMangaSources) {
|
||||||
result.add(
|
result.add(
|
||||||
MangaSourceInfo(
|
MangaSourceInfo(
|
||||||
mangaSource = source,
|
mangaSource = source,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.favourites.domain
|
|||||||
|
|
||||||
import dagger.Reusable
|
import dagger.Reusable
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
|
||||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
import org.koitharu.kotatsu.core.db.entity.toManga
|
import org.koitharu.kotatsu.core.db.entity.toManga
|
||||||
import org.koitharu.kotatsu.core.db.entity.toMangaTags
|
import org.koitharu.kotatsu.core.db.entity.toMangaTags
|
||||||
@@ -18,24 +17,20 @@ import javax.inject.Inject
|
|||||||
class LocalFavoritesObserver @Inject constructor(
|
class LocalFavoritesObserver @Inject constructor(
|
||||||
localMangaIndex: LocalMangaIndex,
|
localMangaIndex: LocalMangaIndex,
|
||||||
private val db: MangaDatabase,
|
private val db: MangaDatabase,
|
||||||
) : LocalObserveMapper<FavouriteManga, Manga>(localMangaIndex, limitStep = 10) {
|
) : LocalObserveMapper<FavouriteManga, Manga>(localMangaIndex) {
|
||||||
|
|
||||||
fun observeAll(
|
fun observeAll(
|
||||||
order: ListSortOrder,
|
order: ListSortOrder,
|
||||||
filterOptions: Set<ListFilterOption>,
|
filterOptions: Set<ListFilterOption>,
|
||||||
limit: Int
|
limit: Int
|
||||||
): Flow<List<Manga>> = db.getFavouritesDao().observeAll(order, filterOptions, limit).mapLatest {
|
): Flow<List<Manga>> = db.getFavouritesDao().observeAll(order, filterOptions, limit).mapToLocal()
|
||||||
it.mapToLocal()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun observeAll(
|
fun observeAll(
|
||||||
categoryId: Long,
|
categoryId: Long,
|
||||||
order: ListSortOrder,
|
order: ListSortOrder,
|
||||||
filterOptions: Set<ListFilterOption>,
|
filterOptions: Set<ListFilterOption>,
|
||||||
limit: Int
|
limit: Int
|
||||||
): Flow<List<Manga>> = db.getFavouritesDao().observeAll(categoryId, order, filterOptions, limit).mapLatest {
|
): Flow<List<Manga>> = db.getFavouritesDao().observeAll(categoryId, order, filterOptions, limit).mapToLocal()
|
||||||
it.mapToLocal()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toManga(e: FavouriteManga) = e.manga.toManga(e.tags.toMangaTags())
|
override fun toManga(e: FavouriteManga) = e.manga.toManga(e.tags.toMangaTags())
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.koitharu.kotatsu.history.data
|
package org.koitharu.kotatsu.history.data
|
||||||
|
|
||||||
import dagger.Reusable
|
import dagger.Reusable
|
||||||
import kotlinx.coroutines.flow.mapLatest
|
|
||||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
import org.koitharu.kotatsu.core.db.entity.toManga
|
import org.koitharu.kotatsu.core.db.entity.toManga
|
||||||
import org.koitharu.kotatsu.core.db.entity.toMangaTags
|
import org.koitharu.kotatsu.core.db.entity.toMangaTags
|
||||||
@@ -17,15 +16,13 @@ import javax.inject.Inject
|
|||||||
class HistoryLocalObserver @Inject constructor(
|
class HistoryLocalObserver @Inject constructor(
|
||||||
localMangaIndex: LocalMangaIndex,
|
localMangaIndex: LocalMangaIndex,
|
||||||
private val db: MangaDatabase,
|
private val db: MangaDatabase,
|
||||||
) : LocalObserveMapper<HistoryWithManga, MangaWithHistory>(localMangaIndex, limitStep = 10) {
|
) : LocalObserveMapper<HistoryWithManga, MangaWithHistory>(localMangaIndex) {
|
||||||
|
|
||||||
fun observeAll(
|
fun observeAll(
|
||||||
order: ListSortOrder,
|
order: ListSortOrder,
|
||||||
filterOptions: Set<ListFilterOption>,
|
filterOptions: Set<ListFilterOption>,
|
||||||
limit: Int
|
limit: Int
|
||||||
) = db.getHistoryDao().observeAll(order, filterOptions, limit).mapLatest {
|
) = db.getHistoryDao().observeAll(order, filterOptions, limit).mapToLocal()
|
||||||
it.mapToLocal()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toManga(e: HistoryWithManga) = e.manga.toManga(e.tags.toMangaTags())
|
override fun toManga(e: HistoryWithManga) = e.manga.toManga(e.tags.toMangaTags())
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,15 @@ import android.content.Context
|
|||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.room.withTransaction
|
import androidx.room.withTransaction
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.FlowCollector
|
import kotlinx.coroutines.flow.FlowCollector
|
||||||
import kotlinx.coroutines.runInterruptible
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
||||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||||
import org.koitharu.kotatsu.local.data.LocalMangaRepository
|
import org.koitharu.kotatsu.local.data.LocalMangaRepository
|
||||||
import org.koitharu.kotatsu.local.data.LocalStorageManager
|
|
||||||
import org.koitharu.kotatsu.local.data.input.LocalMangaInput
|
import org.koitharu.kotatsu.local.data.input.LocalMangaInput
|
||||||
import org.koitharu.kotatsu.local.domain.model.LocalManga
|
import org.koitharu.kotatsu.local.domain.model.LocalManga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
|
||||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -27,7 +23,6 @@ import javax.inject.Singleton
|
|||||||
class LocalMangaIndex @Inject constructor(
|
class LocalMangaIndex @Inject constructor(
|
||||||
private val mangaDataRepository: MangaDataRepository,
|
private val mangaDataRepository: MangaDataRepository,
|
||||||
private val db: MangaDatabase,
|
private val db: MangaDatabase,
|
||||||
private val localStorageManager: LocalStorageManager,
|
|
||||||
@ApplicationContext context: Context,
|
@ApplicationContext context: Context,
|
||||||
private val localMangaRepositoryProvider: Provider<LocalMangaRepository>,
|
private val localMangaRepositoryProvider: Provider<LocalMangaRepository>,
|
||||||
) : FlowCollector<LocalManga?> {
|
) : FlowCollector<LocalManga?> {
|
||||||
@@ -35,9 +30,9 @@ class LocalMangaIndex @Inject constructor(
|
|||||||
private val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
private val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
private var previousHash: Long
|
private var currentVersion: Int
|
||||||
get() = prefs.getLong(KEY_HASH, 0L)
|
get() = prefs.getInt(KEY_VERSION, 0)
|
||||||
set(value) = prefs.edit { putLong(KEY_HASH, value) }
|
set(value) = prefs.edit { putInt(KEY_VERSION, value) }
|
||||||
|
|
||||||
override suspend fun emit(value: LocalManga?) {
|
override suspend fun emit(value: LocalManga?) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
@@ -45,22 +40,25 @@ class LocalMangaIndex @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun update(): Boolean = mutex.withLock {
|
suspend fun update() = mutex.withLock {
|
||||||
val newHash = computeHash()
|
|
||||||
if (newHash == previousHash) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
db.withTransaction {
|
db.withTransaction {
|
||||||
val dao = db.getLocalMangaIndexDao()
|
val dao = db.getLocalMangaIndexDao()
|
||||||
dao.clear()
|
dao.clear()
|
||||||
localMangaRepositoryProvider.get().getRawListAsFlow()
|
localMangaRepositoryProvider.get()
|
||||||
.collect { dao.upsert(it.toEntity()) }
|
.getRawListAsFlow()
|
||||||
|
.collect { upsert(it) }
|
||||||
|
}
|
||||||
|
currentVersion = VERSION
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateIfRequired() {
|
||||||
|
if (isUpdateRequired()) {
|
||||||
|
update()
|
||||||
}
|
}
|
||||||
previousHash = newHash
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun get(mangaId: Long): LocalManga? {
|
suspend fun get(mangaId: Long): LocalManga? {
|
||||||
|
updateIfRequired()
|
||||||
var path = db.getLocalMangaIndexDao().findPath(mangaId)
|
var path = db.getLocalMangaIndexDao().findPath(mangaId)
|
||||||
if (path == null && mutex.isLocked) { // wait for updating complete
|
if (path == null && mutex.isLocked) { // wait for updating complete
|
||||||
path = mutex.withLock { db.getLocalMangaIndexDao().findPath(mangaId) }
|
path = mutex.withLock { db.getLocalMangaIndexDao().findPath(mangaId) }
|
||||||
@@ -77,8 +75,7 @@ class LocalMangaIndex @Inject constructor(
|
|||||||
|
|
||||||
suspend fun put(manga: LocalManga) = mutex.withLock {
|
suspend fun put(manga: LocalManga) = mutex.withLock {
|
||||||
db.withTransaction {
|
db.withTransaction {
|
||||||
mangaDataRepository.storeManga(manga.manga)
|
upsert(manga)
|
||||||
db.getLocalMangaIndexDao().upsert(manga.toEntity())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,27 +87,22 @@ class LocalMangaIndex @Inject constructor(
|
|||||||
return db.getLocalMangaIndexDao().findTags()
|
return db.getLocalMangaIndexDao().findTags()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun upsert(manga: LocalManga) {
|
||||||
|
mangaDataRepository.storeManga(manga.manga)
|
||||||
|
db.getLocalMangaIndexDao().upsert(manga.toEntity())
|
||||||
|
}
|
||||||
|
|
||||||
private fun LocalManga.toEntity() = LocalMangaIndexEntity(
|
private fun LocalManga.toEntity() = LocalMangaIndexEntity(
|
||||||
mangaId = manga.id,
|
mangaId = manga.id,
|
||||||
path = file.path,
|
path = file.path,
|
||||||
)
|
)
|
||||||
|
|
||||||
private suspend fun computeHash(): Long {
|
private fun isUpdateRequired() = currentVersion < VERSION
|
||||||
return runCatchingCancellable {
|
|
||||||
localStorageManager.getReadableDirs()
|
|
||||||
.fold(0L) { acc, file -> acc + file.computeHash() }
|
|
||||||
}.onFailure {
|
|
||||||
it.printStackTraceDebug()
|
|
||||||
}.getOrDefault(0L)
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun File.computeHash(): Long = runInterruptible(Dispatchers.IO) {
|
|
||||||
lastModified() // TODO size
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val PREF_NAME = "_local_index"
|
private const val PREF_NAME = "_local_index"
|
||||||
private const val KEY_HASH = "hash"
|
private const val KEY_VERSION = "ver"
|
||||||
|
private const val VERSION = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,24 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.mapLatest
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
import org.koitharu.kotatsu.core.model.isLocal
|
import org.koitharu.kotatsu.core.model.isLocal
|
||||||
import org.koitharu.kotatsu.local.data.index.LocalMangaIndex
|
import org.koitharu.kotatsu.local.data.index.LocalMangaIndex
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
|
||||||
abstract class LocalObserveMapper<E : Any, R : Any>(
|
abstract class LocalObserveMapper<E : Any, R : Any>(
|
||||||
private val localMangaIndex: LocalMangaIndex,
|
private val localMangaIndex: LocalMangaIndex,
|
||||||
private val limitStep: Int,
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
protected suspend fun List<E>.mapToLocal(): List<R> = coroutineScope {
|
protected fun Flow<Collection<E>>.mapToLocal() = onStart {
|
||||||
|
localMangaIndex.updateIfRequired()
|
||||||
|
}.mapLatest {
|
||||||
|
it.mapToLocal()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun Collection<E>.mapToLocal(): List<R> = coroutineScope {
|
||||||
val dispatcher = Dispatchers.IO.limitedParallelism(6)
|
val dispatcher = Dispatchers.IO.limitedParallelism(6)
|
||||||
map { item ->
|
map { item ->
|
||||||
val m = toManga(item)
|
val m = toManga(item)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.util.LocaleComparator
|
import org.koitharu.kotatsu.core.util.LocaleComparator
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.mapSortedByCount
|
||||||
import org.koitharu.kotatsu.core.util.ext.sortedWithSafe
|
import org.koitharu.kotatsu.core.util.ext.sortedWithSafe
|
||||||
import org.koitharu.kotatsu.core.util.ext.toList
|
import org.koitharu.kotatsu.core.util.ext.toList
|
||||||
import org.koitharu.kotatsu.core.util.ext.toLocale
|
import org.koitharu.kotatsu.core.util.ext.toLocale
|
||||||
@@ -43,15 +44,20 @@ class WelcomeViewModel @Inject constructor(
|
|||||||
|
|
||||||
val types = MutableStateFlow(
|
val types = MutableStateFlow(
|
||||||
FilterProperty(
|
FilterProperty(
|
||||||
availableItems = ContentType.entries.toList(),
|
availableItems = listOf(ContentType.MANGA),
|
||||||
selectedItems = setOf(ContentType.MANGA),
|
selectedItems = setOf(ContentType.MANGA),
|
||||||
isLoading = false,
|
isLoading = true,
|
||||||
error = null,
|
error = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
updateJob = launchJob(Dispatchers.Default) {
|
updateJob = launchJob(Dispatchers.Default) {
|
||||||
|
val contentTypes = allSources.mapSortedByCount { it.contentType }
|
||||||
|
types.value = types.value.copy(
|
||||||
|
availableItems = contentTypes,
|
||||||
|
isLoading = false,
|
||||||
|
)
|
||||||
val languages = localesGroups.keys.associateBy { x -> x.language }
|
val languages = localesGroups.keys.associateBy { x -> x.language }
|
||||||
val selectedLocales = HashSet<Locale>(2)
|
val selectedLocales = HashSet<Locale>(2)
|
||||||
ConfigurationCompat.getLocales(context.resources.configuration).toList()
|
ConfigurationCompat.getLocales(context.resources.configuration).toList()
|
||||||
|
|||||||
@@ -14,20 +14,18 @@ import kotlinx.coroutines.plus
|
|||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.db.MangaDatabase
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
import org.koitharu.kotatsu.core.db.TABLE_SOURCES
|
import org.koitharu.kotatsu.core.db.TABLE_SOURCES
|
||||||
import org.koitharu.kotatsu.core.model.isNsfw
|
|
||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
|
||||||
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
|
||||||
import org.koitharu.kotatsu.core.util.ext.call
|
import org.koitharu.kotatsu.core.util.ext.call
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.mapSortedByCount
|
||||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||||
import org.koitharu.kotatsu.explore.data.SourcesSortOrder
|
import org.koitharu.kotatsu.explore.data.SourcesSortOrder
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||||
import org.koitharu.kotatsu.parsers.model.ContentType
|
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import java.util.EnumMap
|
|
||||||
import java.util.EnumSet
|
import java.util.EnumSet
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -139,13 +137,11 @@ class SourcesCatalogViewModel @Inject constructor(
|
|||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private fun getContentTypes(isNsfwDisabled: Boolean): List<ContentType> {
|
private fun getContentTypes(isNsfwDisabled: Boolean): List<ContentType> {
|
||||||
val map = EnumMap<ContentType, Int>(ContentType::class.java)
|
val result = repository.allMangaSources.mapSortedByCount { it.contentType }
|
||||||
for (e in MangaParserSource.entries) {
|
return if (isNsfwDisabled) {
|
||||||
if (isNsfwDisabled && e.isNsfw()) {
|
result.filterNot { it == ContentType.HENTAI }
|
||||||
continue
|
} else {
|
||||||
}
|
result
|
||||||
map[e.contentType] = map.getOrDefault(e.contentType, 0) + 1
|
|
||||||
}
|
}
|
||||||
return map.entries.sortedByDescending { it.value }.map { it.key }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user