diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index 33956dd1a..6dab7e362 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -245,8 +245,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { val isDownloadsWiFiOnly: Boolean get() = prefs.getBoolean(KEY_DOWNLOADS_WIFI, false) - val isSuggestionsEnabled: Boolean + var isSuggestionsEnabled: Boolean get() = prefs.getBoolean(KEY_SUGGESTIONS, false) + set(value) = prefs.edit { putBoolean(KEY_SUGGESTIONS, value) } val isSuggestionsExcludeNsfw: Boolean get() = prefs.getBoolean(KEY_SUGGESTIONS_EXCLUDE_NSFW, false) @@ -292,19 +293,6 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { return policy.isNetworkAllowed(connectivityManager) } - @Deprecated("") - fun getSuggestionsTagsBlacklistRegex(): Regex? { - val string = prefs.getString(KEY_SUGGESTIONS_EXCLUDE_TAGS, null)?.trimEnd(' ', ',') - if (string.isNullOrEmpty()) { - return null - } - val tags = string.split(',') - val regex = tags.joinToString(prefix = "(", separator = "|", postfix = ")") { tag -> - Regex.escape(tag.trim()) - } - return Regex(regex, RegexOption.IGNORE_CASE) - } - fun getMangaSources(includeHidden: Boolean): List { val list = remoteSources.toMutableList() val order = sourcesOrder diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt b/app/src/main/java/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt index f8bc28e98..4bded9335 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/domain/ExploreRepository.kt @@ -1,11 +1,12 @@ package org.koitharu.kotatsu.explore.domain -import javax.inject.Inject import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.history.domain.HistoryRepository import org.koitharu.kotatsu.parsers.model.Manga import org.koitharu.kotatsu.parsers.model.SortOrder +import org.koitharu.kotatsu.suggestions.domain.TagsBlacklist +import javax.inject.Inject class ExploreRepository @Inject constructor( private val settings: AppSettings, @@ -14,9 +15,9 @@ class ExploreRepository @Inject constructor( ) { suspend fun findRandomManga(tagsLimit: Int): Manga { - val blacklistTagRegex = settings.getSuggestionsTagsBlacklistRegex() + val blacklistTagRegex = TagsBlacklist(settings.suggestionsTagsBlacklist, 0.4f) val allTags = historyRepository.getPopularTags(tagsLimit).filterNot { - blacklistTagRegex?.containsMatchIn(it.title) ?: false + it in blacklistTagRegex } val tag = allTags.randomOrNull() val source = checkNotNull(tag?.source ?: settings.getMangaSources(includeHidden = false).randomOrNull()) { @@ -32,7 +33,7 @@ class ExploreRepository @Inject constructor( if (settings.isSuggestionsExcludeNsfw && item.isNsfw) { continue } - if (blacklistTagRegex != null && item.tags.any { x -> blacklistTagRegex.containsMatchIn(x.title) }) { + if (item in blacklistTagRegex) { continue } return item diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt index 7d8e326b8..618dc4763 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreFragment.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.explore.ui +import android.content.DialogInterface import android.os.Bundle import android.view.LayoutInflater import android.view.MenuItem @@ -16,6 +17,7 @@ import coil.ImageLoader import dagger.hilt.android.AndroidEntryPoint import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment +import org.koitharu.kotatsu.base.ui.dialog.TwoButtonsAlertDialog import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner import org.koitharu.kotatsu.base.ui.util.ReversibleActionObserver @@ -76,6 +78,9 @@ class ExploreFragment : viewModel.onOpenManga.observe(viewLifecycleOwner, ::onOpenManga) viewModel.onActionDone.observe(viewLifecycleOwner, ReversibleActionObserver(binding.recyclerView)) viewModel.isGrid.observe(viewLifecycleOwner, ::onGridModeChanged) + viewModel.onShowSuggestionsTip.observe(viewLifecycleOwner) { + showSuggestionsTip() + } } override fun onDestroyView() { @@ -143,6 +148,19 @@ class ExploreFragment : activity?.invalidateOptionsMenu() } + private fun showSuggestionsTip() { + val listener = DialogInterface.OnClickListener { _, which -> + viewModel.respondSuggestionTip(which == DialogInterface.BUTTON_POSITIVE) + } + TwoButtonsAlertDialog.Builder(requireContext()) + .setIcon(R.drawable.ic_suggestion) + .setTitle(R.string.suggestions_enable_prompt) + .setPositiveButton(R.string.enable, listener) + .setNegativeButton(R.string.no_thanks, listener) + .create() + .show() + } + private inner class SourceMenuListener( private val sourceItem: ExploreItem.Source, ) : PopupMenu.OnMenuItemClickListener { diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt index 4b87979f7..42e3847aa 100644 --- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt @@ -27,6 +27,8 @@ import org.koitharu.kotatsu.utils.SingleLiveEvent import org.koitharu.kotatsu.utils.asFlowLiveData import javax.inject.Inject +private const val TIP_SUGGESTIONS = "suggestions" + @HiltViewModel class ExploreViewModel @Inject constructor( private val settings: AppSettings, @@ -41,6 +43,7 @@ class ExploreViewModel @Inject constructor( val onOpenManga = SingleLiveEvent() val onActionDone = SingleLiveEvent() + val onShowSuggestionsTip = SingleLiveEvent() val isGrid = gridMode.asFlowLiveData(viewModelScope.coroutineContext) val content: LiveData> = isLoading.asFlow().flatMapLatest { loading -> @@ -51,6 +54,14 @@ class ExploreViewModel @Inject constructor( } }.asFlowLiveData(viewModelScope.coroutineContext + Dispatchers.Default, listOf(ExploreItem.Loading)) + init { + launchJob(Dispatchers.Default) { + if (!settings.isSuggestionsEnabled && settings.isTipEnabled(TIP_SUGGESTIONS)) { + onShowSuggestionsTip.emitCall(Unit) + } + } + } + fun openRandom() { launchLoadingJob(Dispatchers.Default) { val manga = exploreRepository.findRandomManga(tagsLimit = 8) @@ -72,6 +83,11 @@ class ExploreViewModel @Inject constructor( settings.isSourcesGridMode = value } + fun respondSuggestionTip(isAccepted: Boolean) { + settings.isSuggestionsEnabled = isAccepted + settings.closeTip(TIP_SUGGESTIONS) + } + private fun createContentFlow() = settings.observe() .filter { it == AppSettings.KEY_SOURCES_HIDDEN || diff --git a/app/src/main/java/org/koitharu/kotatsu/suggestions/domain/TagsBlacklist.kt b/app/src/main/java/org/koitharu/kotatsu/suggestions/domain/TagsBlacklist.kt index baa88d725..691928fa8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/suggestions/domain/TagsBlacklist.kt +++ b/app/src/main/java/org/koitharu/kotatsu/suggestions/domain/TagsBlacklist.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.suggestions.domain import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.parsers.model.MangaTag import org.koitharu.kotatsu.utils.ext.almostEquals class TagsBlacklist( @@ -11,6 +12,9 @@ class TagsBlacklist( fun isNotEmpty() = tags.isNotEmpty() operator fun contains(manga: Manga): Boolean { + if (tags.isEmpty()) { + return false + } for (mangaTag in manga.tags) { for (tagTitle in tags) { if (mangaTag.title.almostEquals(tagTitle, threshold)) { @@ -20,4 +24,8 @@ class TagsBlacklist( } return false } + + operator fun contains(tag: MangaTag): Boolean = tags.any { + it.almostEquals(tag.title, threshold) + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index aa2fb3888..63decf878 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -453,4 +453,5 @@ More Enable No thanks + Do you want to receive personalized manga suggestions?