From 52c39ad40c478540413b8e0ecb54ec7fcd12cf14 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 3 May 2025 10:55:17 +0300 Subject: [PATCH] Ask for one-time incognito for nsfw manga --- .../bookmarks/ui/AllBookmarksFragment.kt | 2 +- .../koitharu/kotatsu/core/nav/ReaderIntent.kt | 4 +- .../kotatsu/core/prefs/AppSettings.kt | 11 ++-- .../details/domain/DetailsInteractor.kt | 22 +++++--- .../kotatsu/details/ui/DetailsActivity.kt | 2 +- .../kotatsu/details/ui/DetailsViewModel.kt | 5 +- .../kotatsu/details/ui/ReadButtonDelegate.kt | 14 +++--- .../ui/pager/ChaptersPagesViewModel.kt | 2 +- .../ui/pager/bookmarks/BookmarksFragment.kt | 2 +- .../explore/data/MangaSourcesRepository.kt | 2 +- .../kotatsu/history/data/HistoryRepository.kt | 6 +-- .../history/domain/HistoryListQuickFilter.kt | 2 +- .../kotatsu/reader/ui/ReaderActivity.kt | 28 +++++++++++ .../kotatsu/reader/ui/ReaderViewModel.kt | 50 +++++++++++++++---- .../userdata/UserDataSettingsFragment.kt | 5 ++ app/src/main/res/values/arrays.xml | 5 ++ app/src/main/res/values/strings.xml | 3 ++ app/src/main/res/xml/pref_user_data.xml | 9 ++-- 18 files changed, 128 insertions(+), 46 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt index 8c04ff471..cd43e2038 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/bookmarks/ui/AllBookmarksFragment.kt @@ -123,7 +123,7 @@ class AllBookmarksFragment : if (selectionController?.onItemClick(item.pageId) != true) { val intent = ReaderIntent.Builder(view.context) .bookmark(item) - .incognito(true) + .incognito() .build() router.openReader(intent) Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/ReaderIntent.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/ReaderIntent.kt index d1607a55a..407e293c7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/ReaderIntent.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/nav/ReaderIntent.kt @@ -27,8 +27,8 @@ value class ReaderIntent private constructor( intent.putExtra(AppRouter.KEY_ID, mangaId) } - fun incognito(incognito: Boolean) = apply { - intent.putExtra(EXTRA_INCOGNITO, incognito) + fun incognito() = apply { + intent.putExtra(EXTRA_INCOGNITO, true) } fun branch(branch: String?) = apply { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt index cee5fda63..a66596bf6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -214,8 +214,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { val progressIndicatorMode: ProgressIndicatorMode get() = prefs.getEnumValue(KEY_PROGRESS_INDICATORS, ProgressIndicatorMode.PERCENT_READ) - val isHistoryExcludeNsfw: Boolean - get() = prefs.getBoolean(KEY_HISTORY_EXCLUDE_NSFW, false) + var incognitoModeForNsfw: TriStateOption + get() = prefs.getEnumValue(KEY_INCOGNITO_NSFW, TriStateOption.ASK) + set(value) = prefs.edit { putEnumValue(KEY_INCOGNITO_NSFW, value) } var isIncognitoModeEnabled: Boolean get() = prefs.getBoolean(KEY_INCOGNITO_MODE, false) @@ -545,6 +546,10 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { prefs.edit { putStringSet(KEY_TIPS_CLOSED, closedTips + tip) } } + fun isIncognitoModeEnabled(isNsfw: Boolean): Boolean { + return isIncognitoModeEnabled || (isNsfw && incognitoModeForNsfw == TriStateOption.ENABLED) + } + fun getPagesSaveDir(context: Context): DocumentFile? = prefs.getString(KEY_PAGES_SAVE_DIR, null)?.toUriOrNull()?.let { DocumentFile.fromTreeUri(context, it)?.takeIf { it.canWrite() } @@ -656,7 +661,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) { const val KEY_PROGRESS_INDICATORS = "progress_indicators" const val KEY_REVERSE_CHAPTERS = "reverse_chapters" const val KEY_GRID_VIEW_CHAPTERS = "grid_view_chapters" - const val KEY_HISTORY_EXCLUDE_NSFW = "history_exclude_nsfw" + const val KEY_INCOGNITO_NSFW = "incognito_nsfw" const val KEY_PAGES_NUMBERS = "pages_numbers" const val KEY_SCREENSHOTS_POLICY = "screenshots_policy" const val KEY_PAGES_PRELOAD = "pages_preload" diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt index f48a668df..e8c1aa04f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/domain/DetailsInteractor.kt @@ -3,10 +3,13 @@ package org.koitharu.kotatsu.details.domain import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.filterNotNull import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.core.model.isNsfw import org.koitharu.kotatsu.core.prefs.AppSettings +import org.koitharu.kotatsu.core.prefs.TriStateOption import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.details.data.MangaDetails import org.koitharu.kotatsu.favourites.domain.FavouritesRepository @@ -53,14 +56,15 @@ class DetailsInteractor @Inject constructor( } } - fun observeIncognitoMode(mangaFlow: Flow): Flow { + fun observeIncognitoMode(mangaFlow: Flow): Flow { return mangaFlow - .distinctUntilChangedBy { it?.isNsfw } - .flatMapLatest { manga -> - if (manga != null) { - historyRepository.observeShouldSkip(manga) - } else { - settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled } + .filterNotNull() + .distinctUntilChangedBy { it.isNsfw() } + .combine(observeIncognitoMode()) { manga, globalIncognito -> + when { + globalIncognito -> TriStateOption.ENABLED + manga.isNsfw() -> settings.incognitoModeForNsfw + else -> TriStateOption.DISABLED } } } @@ -87,4 +91,8 @@ class DetailsInteractor @Inject constructor( } suspend fun findRemote(seed: Manga) = localMangaRepository.getRemoteManga(seed) + + private fun observeIncognitoMode() = settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { + isIncognitoModeEnabled + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index b92ec6a66..4fd4c0212 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -263,7 +263,7 @@ class DetailsActivity : } override fun onItemClick(item: Bookmark, view: View) { - router.openReader(ReaderIntent.Builder(view.context).bookmark(item).incognito(true).build()) + router.openReader(ReaderIntent.Builder(view.context).bookmark(item).incognito().build()) Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index c09d356a3..22752dd0a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -24,6 +24,7 @@ import org.koitharu.kotatsu.core.model.getPreferredBranch import org.koitharu.kotatsu.core.nav.MangaIntent import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode +import org.koitharu.kotatsu.core.prefs.TriStateOption import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.computeSize @@ -63,7 +64,7 @@ class DetailsViewModel @Inject constructor( private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>, @LocalStorageChanges localStorageChanges: SharedFlow, downloadScheduler: DownloadWorker.Scheduler, - private val interactor: DetailsInteractor, + interactor: DetailsInteractor, savedStateHandle: SavedStateHandle, deleteLocalMangaUseCase: DeleteLocalMangaUseCase, private val relatedMangaUseCase: RelatedMangaUseCase, @@ -113,7 +114,7 @@ class DetailsViewModel @Inject constructor( interactor.observeIncognitoMode(manga), ) { m, b, h, im -> val estimatedTime = readingTimeUseCase.invoke(m, b, h) - HistoryInfo(m, b, h, im, estimatedTime) + HistoryInfo(m, b, h, im == TriStateOption.ENABLED, estimatedTime) }.withErrorHandling() .stateIn( scope = viewModelScope + Dispatchers.Default, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt index 045461f4f..2a1054ac8 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/ReadButtonDelegate.kt @@ -111,13 +111,13 @@ class ReadButtonDelegate( Snackbar.make(buttonRead, R.string.chapter_is_missing, Snackbar.LENGTH_SHORT) .show() // TODO } else { - router.openReader( - ReaderIntent.Builder(context) - .manga(manga) - .branch(viewModel.selectedBranchValue) - .incognito(isIncognitoMode) - .build(), - ) + val intentBuilder = ReaderIntent.Builder(context) + .manga(manga) + .branch(viewModel.selectedBranchValue) + if (isIncognitoMode) { + intentBuilder.incognito() + } + router.openReader(intentBuilder.build()) if (isIncognitoMode) { Toast.makeText(context, R.string.incognito_mode, Toast.LENGTH_SHORT).show() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt index 2e6979c10..1bf211756 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt @@ -49,7 +49,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderViewModel abstract class ChaptersPagesViewModel( @JvmField protected val settings: AppSettings, - private val interactor: DetailsInteractor, + @JvmField protected val interactor: DetailsInteractor, private val bookmarksRepository: BookmarksRepository, private val historyRepository: HistoryRepository, private val downloadScheduler: DownloadWorker.Scheduler, diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt index 504d8e1c6..a1cd3671d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/bookmarks/BookmarksFragment.kt @@ -140,7 +140,7 @@ class BookmarksFragment : BaseFragment(), val intent = ReaderIntent.Builder(view.context) .manga(activityViewModel.getMangaOrNull() ?: return) .bookmark(item) - .incognito(true) + .incognito() .build() router.openReader(intent) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/explore/data/MangaSourcesRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/explore/data/MangaSourcesRepository.kt index 9f59ed56e..6f01a768b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/explore/data/MangaSourcesRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/explore/data/MangaSourcesRepository.kt @@ -288,7 +288,7 @@ class MangaSourcesRepository @Inject constructor( } suspend fun trackUsage(source: MangaSource) { - if (!settings.isIncognitoModeEnabled && !(settings.isHistoryExcludeNsfw && source.isNsfw())) { + if (!settings.isIncognitoModeEnabled(source.isNsfw())) { dao.setLastUsed(source.name, System.currentTimeMillis()) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt index 1ba9c4b0d..c3d1c9298 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/data/HistoryRepository.kt @@ -201,13 +201,11 @@ class HistoryRepository @Inject constructor( return db.getHistoryDao().findPopularSources(limit).toMangaSources() } - fun shouldSkip(manga: Manga): Boolean { - return ((manga.source.isNsfw() || manga.isNsfw) && settings.isHistoryExcludeNsfw) || settings.isIncognitoModeEnabled - } + fun shouldSkip(manga: Manga): Boolean = settings.isIncognitoModeEnabled(manga.isNsfw()) fun observeShouldSkip(manga: Manga): Flow { return settings.observe() - .filter { key -> key == AppSettings.KEY_INCOGNITO_MODE || key == AppSettings.KEY_HISTORY_EXCLUDE_NSFW } + .filter { key -> key == AppSettings.KEY_INCOGNITO_MODE || key == AppSettings.KEY_INCOGNITO_NSFW } .onStart { emit("") } .map { shouldSkip(manga) } .distinctUntilChanged() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryListQuickFilter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryListQuickFilter.kt index bf0ae0ccf..bfa68949b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryListQuickFilter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/history/domain/HistoryListQuickFilter.kt @@ -25,7 +25,7 @@ class HistoryListQuickFilter @Inject constructor( add(ListFilterOption.Macro.COMPLETED) add(ListFilterOption.Macro.FAVORITE) add(ListFilterOption.NOT_FAVORITE) - if (!settings.isNsfwContentDisabled && !settings.isHistoryExcludeNsfw) { + if (!settings.isNsfwContentDisabled) { add(ListFilterOption.Macro.NSFW) } repository.getPopularTags(3).mapTo(this) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index 88273178d..371d21514 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -1,5 +1,6 @@ package org.koitharu.kotatsu.reader.ui +import android.content.DialogInterface import android.content.Intent import android.os.Bundle import android.view.Gravity @@ -35,6 +36,8 @@ import org.koitharu.kotatsu.core.nav.router import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.ui.BaseFullscreenActivity +import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog +import org.koitharu.kotatsu.core.ui.dialog.setCheckbox import org.koitharu.kotatsu.core.ui.util.MenuInvalidator import org.koitharu.kotatsu.core.ui.widgets.ZoomControl import org.koitharu.kotatsu.core.util.IdlingDetector @@ -145,6 +148,7 @@ class ReaderActivity : viewModel.isInfoBarTransparent.observe(this) { viewBinding.infoBar.drawBackground = !it } viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged) viewModel.isBookmarkAdded.observe(this, MenuInvalidator(this)) + viewModel.onAskNsfwIncognito.observeEvent(this) { askForIncognitoMode() } viewModel.onShowToast.observeEvent(this) { msgId -> Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT) .setAnchorView(viewBinding.toolbarDocked) @@ -432,6 +436,30 @@ class ReaderActivity : viewBinding.actionsView.isPrevEnabled = uiState.hasPreviousChapter() } + private fun askForIncognitoMode() { + buildAlertDialog(this, isCentered = true) { + var dontAskAgain = false + val listener = DialogInterface.OnClickListener { _, which -> + if (which == DialogInterface.BUTTON_NEUTRAL) { + finishAfterTransition() + } else { + viewModel.setIncognitoMode(which == DialogInterface.BUTTON_POSITIVE, dontAskAgain) + } + } + setCheckbox(R.string.dont_ask_again, dontAskAgain) { _, isChecked -> + dontAskAgain = isChecked + } + setIcon(R.drawable.ic_incognito) + setTitle(R.string.incognito_mode) + setMessage(R.string.incognito_mode_hint_nsfw) + setPositiveButton(R.string.incognito, listener) + setNegativeButton(R.string.disable, listener) + setNeutralButton(android.R.string.cancel, listener) + setOnCancelListener { finishAfterTransition() } + setCancelable(true) + }.show() + } + companion object { private const val TOAST_DURATION = 2000L diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt index fe5d96bb7..14b478147 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderViewModel.kt @@ -35,10 +35,12 @@ import org.koitharu.kotatsu.core.os.AppShortcutManager import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode +import org.koitharu.kotatsu.core.prefs.TriStateOption import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.core.util.ext.firstNotNull import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.details.data.MangaDetails import org.koitharu.kotatsu.details.domain.DetailsInteractor @@ -112,14 +114,10 @@ class ReaderViewModel @Inject constructor( val readerMode = MutableStateFlow(null) val onPageSaved = MutableEventFlow>() val onShowToast = MutableEventFlow() + val onAskNsfwIncognito = MutableEventFlow() val uiState = MutableStateFlow(null) - val incognitoMode = if (savedStateHandle.get(ReaderIntent.EXTRA_INCOGNITO) == true) { - MutableStateFlow(true) - } else { - interactor.observeIncognitoMode(manga) - .stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) - } + val isIncognitoMode = MutableStateFlow(savedStateHandle.get(ReaderIntent.EXTRA_INCOGNITO)) val content = MutableStateFlow(ReaderContent(emptyList(), null)) @@ -191,10 +189,13 @@ class ReaderViewModel @Inject constructor( }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) init { + initIncognitoMode() loadImpl() launchJob(Dispatchers.Default) { val mangaId = manga.filterNotNull().first().id - appShortcutManager.notifyMangaOpened(mangaId) + if (!isIncognitoMode.firstNotNull()) { + appShortcutManager.notifyMangaOpened(mangaId) + } } } @@ -228,7 +229,7 @@ class ReaderViewModel @Inject constructor( readingState.value = state savedStateHandle[ReaderIntent.EXTRA_STATE] = state } - if (incognitoMode.value) { + if (isIncognitoMode.value != false) { return } val readerState = state ?: readingState.value ?: return @@ -381,6 +382,13 @@ class ReaderViewModel @Inject constructor( } } + fun setIncognitoMode(value: Boolean, dontAskAgain: Boolean) { + isIncognitoMode.value = value + if (dontAskAgain) { + settings.incognitoModeForNsfw = if (value) TriStateOption.ENABLED else TriStateOption.DISABLED + } + } + private fun loadImpl() { loadingJob = launchLoadingJob(Dispatchers.Default) { val details = detailsLoadUseCase.invoke(intent, force = false).first { x -> x.isLoaded } @@ -399,7 +407,7 @@ class ReaderViewModel @Inject constructor( chaptersLoader.loadSingleChapter(requireNotNull(readingState.value).chapterId) // save state - if (!incognitoMode.value) { + if (!isIncognitoMode.firstNotNull()) { readingState.value?.let { val percent = computePercent(it.chapterId, it.page) historyUpdateUseCase.invoke(manga, it, percent) @@ -444,10 +452,10 @@ class ReaderViewModel @Inject constructor( totalPages = chaptersLoader.getPagesCount(chapter.id), currentPage = state.page, percent = computePercent(state.chapterId, state.page), - incognito = incognitoMode.value, + incognito = isIncognitoMode.value == true, ) uiState.value = newState - if (!incognitoMode.value) { + if (isIncognitoMode.value == false) { statsCollector.onStateChanged(m.id, state) } } @@ -481,6 +489,26 @@ class ReaderViewModel @Inject constructor( valueProducer = { isReaderZoomButtonsEnabled }, ) + private fun initIncognitoMode() { + if (isIncognitoMode.value != null) { + return + } + launchJob(Dispatchers.Default) { + interactor.observeIncognitoMode(manga) + .collect { + when (it) { + TriStateOption.ENABLED -> isIncognitoMode.value = true + TriStateOption.ASK -> { + onAskNsfwIncognito.call(Unit) + return@collect + } + + TriStateOption.DISABLED -> isIncognitoMode.value = false + } + } + } + } + private suspend fun getStateFromIntent(manga: Manga): ReaderState { val history = historyRepository.getOne(manga) val preselectedBranch = selectedBranch.value diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/userdata/UserDataSettingsFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/userdata/UserDataSettingsFragment.kt index 2c9863100..584be65b9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/userdata/UserDataSettingsFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/userdata/UserDataSettingsFragment.kt @@ -21,6 +21,7 @@ import org.koitharu.kotatsu.core.os.AppShortcutManager import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ScreenshotsPolicy import org.koitharu.kotatsu.core.prefs.SearchSuggestionType +import org.koitharu.kotatsu.core.prefs.TriStateOption import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.ext.observe @@ -58,6 +59,10 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac entryValues = ScreenshotsPolicy.entries.names() setDefaultValueCompat(ScreenshotsPolicy.ALLOW.name) } + findPreference(AppSettings.KEY_INCOGNITO_NSFW)?.run { + entryValues = TriStateOption.entries.names() + setDefaultValueCompat(TriStateOption.ASK.name) + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index edc12d447..fb8fd705d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -137,4 +137,9 @@ @string/favourites @string/saved_manga + + @string/enable + @string/ask_every_time + @string/disable + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bfc3d757b..0e45db0eb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -832,4 +832,7 @@ Pick custom file Change cover The page will switch every ~%d seconds + Don\'t ask again + This manga may contain adult content. Do you want to use incognito mode? + Incognito mode for NSFW manga diff --git a/app/src/main/res/xml/pref_user_data.xml b/app/src/main/res/xml/pref_user_data.xml index 529a902e3..27a7aec4f 100644 --- a/app/src/main/res/xml/pref_user_data.xml +++ b/app/src/main/res/xml/pref_user_data.xml @@ -17,10 +17,11 @@ android:title="@string/screenshots_policy" app:useSimpleSummaryProvider="true" /> - +