Option to open random manga from source

This commit is contained in:
Koitharu
2023-07-28 12:15:03 +03:00
parent f105f4b496
commit 2378d104c3
5 changed files with 72 additions and 5 deletions

View File

@@ -7,6 +7,7 @@ import org.koitharu.kotatsu.core.util.ext.asArrayList
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.history.data.HistoryRepository
import org.koitharu.kotatsu.parsers.model.ContentType
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
@@ -21,19 +22,39 @@ class ExploreRepository @Inject constructor(
) {
suspend fun findRandomManga(tagsLimit: Int): Manga {
val blacklistTagRegex = TagsBlacklist(settings.suggestionsTagsBlacklist, 0.4f)
val tagsBlacklist = TagsBlacklist(settings.suggestionsTagsBlacklist, 0.4f)
val tags = historyRepository.getPopularTags(tagsLimit).mapNotNull {
if (it in blacklistTagRegex) null else it.title
if (it in tagsBlacklist) null else it.title
}
val sources = sourcesRepository.getEnabledSources()
check(sources.isNotEmpty()) { "No sources available" }
for (i in 0..4) {
val list = getList(sources.random(), tags, blacklistTagRegex)
val list = getList(sources.random(), tags, tagsBlacklist)
val manga = list.randomOrNull() ?: continue
val details = runCatchingCancellable {
mangaRepositoryFactory.create(manga.source).getDetails(manga)
}.getOrNull() ?: continue
if ((settings.isSuggestionsExcludeNsfw && details.isNsfw) || details in blacklistTagRegex) {
if ((settings.isSuggestionsExcludeNsfw && details.isNsfw) || details in tagsBlacklist) {
continue
}
return details
}
throw NoSuchElementException()
}
suspend fun findRandomManga(source: MangaSource, tagsLimit: Int): Manga {
val tagsBlacklist = TagsBlacklist(settings.suggestionsTagsBlacklist, 0.4f)
val skipNsfw = settings.isSuggestionsExcludeNsfw && source.contentType != ContentType.HENTAI
val tags = historyRepository.getPopularTags(tagsLimit).mapNotNull {
if (it in tagsBlacklist) null else it.title
}
for (i in 0..4) {
val list = getList(source, tags, tagsBlacklist)
val manga = list.randomOrNull() ?: continue
val details = runCatchingCancellable {
mangaRepositoryFactory.create(manga.source).getDetails(manga)
}.getOrNull() ?: continue
if ((skipNsfw && details.isNsfw) || details in tagsBlacklist) {
continue
}
return details

View File

@@ -11,6 +11,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.explore.domain.ExploreRepository
import org.koitharu.kotatsu.filter.ui.FilterCoordinator
import org.koitharu.kotatsu.list.domain.ListExtraProvider
import org.koitharu.kotatsu.list.ui.model.EmptyState
@@ -29,6 +30,7 @@ class LocalListViewModel @Inject constructor(
downloadScheduler: DownloadWorker.Scheduler,
listExtraProvider: ListExtraProvider,
private val deleteLocalMangaUseCase: DeleteLocalMangaUseCase,
exploreRepository: ExploreRepository,
@LocalStorageChanges private val localStorageChanges: SharedFlow<LocalManga?>,
) : RemoteListViewModel(
savedStateHandle,
@@ -37,6 +39,7 @@ class LocalListViewModel @Inject constructor(
settings,
listExtraProvider,
downloadScheduler,
exploreRepository,
), SharedPreferences.OnSharedPreferenceChangeListener {
val onMangaRemoved = MutableEventFlow<Unit>()

View File

@@ -12,9 +12,13 @@ import androidx.fragment.app.viewModels
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.list.ListSelectionController
import org.koitharu.kotatsu.core.ui.util.MenuInvalidator
import org.koitharu.kotatsu.core.util.ext.addMenuProvider
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.observeEvent
import org.koitharu.kotatsu.core.util.ext.withArgs
import org.koitharu.kotatsu.databinding.FragmentListBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.filter.ui.FilterOwner
import org.koitharu.kotatsu.filter.ui.FilterSheetFragment
import org.koitharu.kotatsu.filter.ui.MangaFilter
@@ -35,6 +39,10 @@ class RemoteListFragment : MangaListFragment(), FilterOwner {
override fun onViewBindingCreated(binding: FragmentListBinding, savedInstanceState: Bundle?) {
super.onViewBindingCreated(binding, savedInstanceState)
addMenuProvider(RemoteListMenuProvider())
viewModel.isRandomLoading.observe(viewLifecycleOwner, MenuInvalidator(requireActivity()))
viewModel.onOpenManga.observeEvent(viewLifecycleOwner) {
startActivity(DetailsActivity.newIntent(binding.root.context, it))
}
}
override fun onScrolledToEnd() {
@@ -75,6 +83,11 @@ class RemoteListFragment : MangaListFragment(), FilterOwner {
true
}
R.id.action_random -> {
viewModel.openRandom()
true
}
R.id.action_filter -> {
onFilterClick(null)
true
@@ -83,6 +96,11 @@ class RemoteListFragment : MangaListFragment(), FilterOwner {
else -> false
}
override fun onPrepareMenu(menu: Menu) {
super.onPrepareMenu(menu)
menu.findItem(R.id.action_random)?.isEnabled = !viewModel.isRandomLoading.value
}
override fun onQueryTextSubmit(query: String?): Boolean {
if (query.isNullOrEmpty()) {
return false

View File

@@ -19,10 +19,12 @@ import kotlinx.coroutines.plus
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
import org.koitharu.kotatsu.explore.domain.ExploreRepository
import org.koitharu.kotatsu.filter.ui.FilterCoordinator
import org.koitharu.kotatsu.filter.ui.MangaFilter
import org.koitharu.kotatsu.filter.ui.model.FilterState
@@ -49,14 +51,19 @@ open class RemoteListViewModel @Inject constructor(
settings: AppSettings,
listExtraProvider: ListExtraProvider,
downloadScheduler: DownloadWorker.Scheduler,
private val exploreRepository: ExploreRepository,
) : MangaListViewModel(settings, downloadScheduler), MangaFilter by filter {
val source = savedStateHandle.require<MangaSource>(RemoteListFragment.ARG_SOURCE)
val isRandomLoading = MutableStateFlow(false)
val onOpenManga = MutableEventFlow<Manga>()
private val repository = mangaRepositoryFactory.create(source)
private val mangaList = MutableStateFlow<List<Manga>?>(null)
private val hasNextPage = MutableStateFlow(false)
private val listError = MutableStateFlow<Throwable?>(null)
private var loadingJob: Job? = null
private var randomJob: Job? = null
override val content = combine(
mangaList,
@@ -149,4 +156,16 @@ open class RemoteListViewModel @Inject constructor(
textSecondary = 0,
actionStringRes = if (canResetFilter) R.string.reset_filter else 0,
)
fun openRandom() {
if (randomJob?.isActive == true) {
return
}
randomJob = launchLoadingJob(Dispatchers.Default) {
isRandomLoading.value = true
val manga = exploreRepository.findRandomManga(source, 16)
onOpenManga.call(manga)
isRandomLoading.value = false
}
}
}

View File

@@ -10,6 +10,12 @@
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" />
<item
android:id="@+id/action_random"
android:icon="@drawable/ic_dice"
android:title="@string/random"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_filter"
android:orderInCategory="30"
@@ -21,4 +27,4 @@
android:orderInCategory="50"
android:title="@string/settings"
app:showAsAction="never" />
</menu>
</menu>