Option to open random manga from source
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user