Ask for one-time incognito for nsfw manga

master
Koitharu 1 year ago
parent 842ecaaff6
commit 52c39ad40c
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -123,7 +123,7 @@ class AllBookmarksFragment :
if (selectionController?.onItemClick(item.pageId) != true) { if (selectionController?.onItemClick(item.pageId) != true) {
val intent = ReaderIntent.Builder(view.context) val intent = ReaderIntent.Builder(view.context)
.bookmark(item) .bookmark(item)
.incognito(true) .incognito()
.build() .build()
router.openReader(intent) router.openReader(intent)
Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show() Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show()

@ -27,8 +27,8 @@ value class ReaderIntent private constructor(
intent.putExtra(AppRouter.KEY_ID, mangaId) intent.putExtra(AppRouter.KEY_ID, mangaId)
} }
fun incognito(incognito: Boolean) = apply { fun incognito() = apply {
intent.putExtra(EXTRA_INCOGNITO, incognito) intent.putExtra(EXTRA_INCOGNITO, true)
} }
fun branch(branch: String?) = apply { fun branch(branch: String?) = apply {

@ -214,8 +214,9 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
val progressIndicatorMode: ProgressIndicatorMode val progressIndicatorMode: ProgressIndicatorMode
get() = prefs.getEnumValue(KEY_PROGRESS_INDICATORS, ProgressIndicatorMode.PERCENT_READ) get() = prefs.getEnumValue(KEY_PROGRESS_INDICATORS, ProgressIndicatorMode.PERCENT_READ)
val isHistoryExcludeNsfw: Boolean var incognitoModeForNsfw: TriStateOption
get() = prefs.getBoolean(KEY_HISTORY_EXCLUDE_NSFW, false) get() = prefs.getEnumValue(KEY_INCOGNITO_NSFW, TriStateOption.ASK)
set(value) = prefs.edit { putEnumValue(KEY_INCOGNITO_NSFW, value) }
var isIncognitoModeEnabled: Boolean var isIncognitoModeEnabled: Boolean
get() = prefs.getBoolean(KEY_INCOGNITO_MODE, false) 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) } prefs.edit { putStringSet(KEY_TIPS_CLOSED, closedTips + tip) }
} }
fun isIncognitoModeEnabled(isNsfw: Boolean): Boolean {
return isIncognitoModeEnabled || (isNsfw && incognitoModeForNsfw == TriStateOption.ENABLED)
}
fun getPagesSaveDir(context: Context): DocumentFile? = fun getPagesSaveDir(context: Context): DocumentFile? =
prefs.getString(KEY_PAGES_SAVE_DIR, null)?.toUriOrNull()?.let { prefs.getString(KEY_PAGES_SAVE_DIR, null)?.toUriOrNull()?.let {
DocumentFile.fromTreeUri(context, it)?.takeIf { it.canWrite() } 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_PROGRESS_INDICATORS = "progress_indicators"
const val KEY_REVERSE_CHAPTERS = "reverse_chapters" const val KEY_REVERSE_CHAPTERS = "reverse_chapters"
const val KEY_GRID_VIEW_CHAPTERS = "grid_view_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_PAGES_NUMBERS = "pages_numbers"
const val KEY_SCREENSHOTS_POLICY = "screenshots_policy" const val KEY_SCREENSHOTS_POLICY = "screenshots_policy"
const val KEY_PAGES_PRELOAD = "pages_preload" const val KEY_PAGES_PRELOAD = "pages_preload"

@ -3,10 +3,13 @@ package org.koitharu.kotatsu.details.domain
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf
import org.koitharu.kotatsu.core.model.FavouriteCategory 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.AppSettings
import org.koitharu.kotatsu.core.prefs.TriStateOption
import org.koitharu.kotatsu.core.prefs.observeAsFlow import org.koitharu.kotatsu.core.prefs.observeAsFlow
import org.koitharu.kotatsu.details.data.MangaDetails import org.koitharu.kotatsu.details.data.MangaDetails
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
@ -53,14 +56,15 @@ class DetailsInteractor @Inject constructor(
} }
} }
fun observeIncognitoMode(mangaFlow: Flow<Manga?>): Flow<Boolean> { fun observeIncognitoMode(mangaFlow: Flow<Manga?>): Flow<TriStateOption> {
return mangaFlow return mangaFlow
.distinctUntilChangedBy { it?.isNsfw } .filterNotNull()
.flatMapLatest { manga -> .distinctUntilChangedBy { it.isNsfw() }
if (manga != null) { .combine(observeIncognitoMode()) { manga, globalIncognito ->
historyRepository.observeShouldSkip(manga) when {
} else { globalIncognito -> TriStateOption.ENABLED
settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) { isIncognitoModeEnabled } manga.isNsfw() -> settings.incognitoModeForNsfw
else -> TriStateOption.DISABLED
} }
} }
} }
@ -87,4 +91,8 @@ class DetailsInteractor @Inject constructor(
} }
suspend fun findRemote(seed: Manga) = localMangaRepository.getRemoteManga(seed) suspend fun findRemote(seed: Manga) = localMangaRepository.getRemoteManga(seed)
private fun observeIncognitoMode() = settings.observeAsFlow(AppSettings.KEY_INCOGNITO_MODE) {
isIncognitoModeEnabled
}
} }

@ -263,7 +263,7 @@ class DetailsActivity :
} }
override fun onItemClick(item: Bookmark, view: View) { 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() Toast.makeText(view.context, R.string.incognito_mode, Toast.LENGTH_SHORT).show()
} }

@ -24,6 +24,7 @@ import org.koitharu.kotatsu.core.model.getPreferredBranch
import org.koitharu.kotatsu.core.nav.MangaIntent import org.koitharu.kotatsu.core.nav.MangaIntent
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode 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.ui.util.ReversibleAction
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.computeSize import org.koitharu.kotatsu.core.util.ext.computeSize
@ -63,7 +64,7 @@ class DetailsViewModel @Inject constructor(
private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>, private val scrobblers: Set<@JvmSuppressWildcards Scrobbler>,
@LocalStorageChanges localStorageChanges: SharedFlow<LocalManga?>, @LocalStorageChanges localStorageChanges: SharedFlow<LocalManga?>,
downloadScheduler: DownloadWorker.Scheduler, downloadScheduler: DownloadWorker.Scheduler,
private val interactor: DetailsInteractor, interactor: DetailsInteractor,
savedStateHandle: SavedStateHandle, savedStateHandle: SavedStateHandle,
deleteLocalMangaUseCase: DeleteLocalMangaUseCase, deleteLocalMangaUseCase: DeleteLocalMangaUseCase,
private val relatedMangaUseCase: RelatedMangaUseCase, private val relatedMangaUseCase: RelatedMangaUseCase,
@ -113,7 +114,7 @@ class DetailsViewModel @Inject constructor(
interactor.observeIncognitoMode(manga), interactor.observeIncognitoMode(manga),
) { m, b, h, im -> ) { m, b, h, im ->
val estimatedTime = readingTimeUseCase.invoke(m, b, h) val estimatedTime = readingTimeUseCase.invoke(m, b, h)
HistoryInfo(m, b, h, im, estimatedTime) HistoryInfo(m, b, h, im == TriStateOption.ENABLED, estimatedTime)
}.withErrorHandling() }.withErrorHandling()
.stateIn( .stateIn(
scope = viewModelScope + Dispatchers.Default, scope = viewModelScope + Dispatchers.Default,

@ -111,13 +111,13 @@ class ReadButtonDelegate(
Snackbar.make(buttonRead, R.string.chapter_is_missing, Snackbar.LENGTH_SHORT) Snackbar.make(buttonRead, R.string.chapter_is_missing, Snackbar.LENGTH_SHORT)
.show() // TODO .show() // TODO
} else { } else {
router.openReader( val intentBuilder = ReaderIntent.Builder(context)
ReaderIntent.Builder(context) .manga(manga)
.manga(manga) .branch(viewModel.selectedBranchValue)
.branch(viewModel.selectedBranchValue) if (isIncognitoMode) {
.incognito(isIncognitoMode) intentBuilder.incognito()
.build(), }
) router.openReader(intentBuilder.build())
if (isIncognitoMode) { if (isIncognitoMode) {
Toast.makeText(context, R.string.incognito_mode, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.incognito_mode, Toast.LENGTH_SHORT).show()
} }

@ -49,7 +49,7 @@ import org.koitharu.kotatsu.reader.ui.ReaderViewModel
abstract class ChaptersPagesViewModel( abstract class ChaptersPagesViewModel(
@JvmField protected val settings: AppSettings, @JvmField protected val settings: AppSettings,
private val interactor: DetailsInteractor, @JvmField protected val interactor: DetailsInteractor,
private val bookmarksRepository: BookmarksRepository, private val bookmarksRepository: BookmarksRepository,
private val historyRepository: HistoryRepository, private val historyRepository: HistoryRepository,
private val downloadScheduler: DownloadWorker.Scheduler, private val downloadScheduler: DownloadWorker.Scheduler,

@ -140,7 +140,7 @@ class BookmarksFragment : BaseFragment<FragmentMangaBookmarksBinding>(),
val intent = ReaderIntent.Builder(view.context) val intent = ReaderIntent.Builder(view.context)
.manga(activityViewModel.getMangaOrNull() ?: return) .manga(activityViewModel.getMangaOrNull() ?: return)
.bookmark(item) .bookmark(item)
.incognito(true) .incognito()
.build() .build()
router.openReader(intent) router.openReader(intent)
} }

@ -288,7 +288,7 @@ class MangaSourcesRepository @Inject constructor(
} }
suspend fun trackUsage(source: MangaSource) { suspend fun trackUsage(source: MangaSource) {
if (!settings.isIncognitoModeEnabled && !(settings.isHistoryExcludeNsfw && source.isNsfw())) { if (!settings.isIncognitoModeEnabled(source.isNsfw())) {
dao.setLastUsed(source.name, System.currentTimeMillis()) dao.setLastUsed(source.name, System.currentTimeMillis())
} }
} }

@ -201,13 +201,11 @@ class HistoryRepository @Inject constructor(
return db.getHistoryDao().findPopularSources(limit).toMangaSources() return db.getHistoryDao().findPopularSources(limit).toMangaSources()
} }
fun shouldSkip(manga: Manga): Boolean { fun shouldSkip(manga: Manga): Boolean = settings.isIncognitoModeEnabled(manga.isNsfw())
return ((manga.source.isNsfw() || manga.isNsfw) && settings.isHistoryExcludeNsfw) || settings.isIncognitoModeEnabled
}
fun observeShouldSkip(manga: Manga): Flow<Boolean> { fun observeShouldSkip(manga: Manga): Flow<Boolean> {
return settings.observe() 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("") } .onStart { emit("") }
.map { shouldSkip(manga) } .map { shouldSkip(manga) }
.distinctUntilChanged() .distinctUntilChanged()

@ -25,7 +25,7 @@ class HistoryListQuickFilter @Inject constructor(
add(ListFilterOption.Macro.COMPLETED) add(ListFilterOption.Macro.COMPLETED)
add(ListFilterOption.Macro.FAVORITE) add(ListFilterOption.Macro.FAVORITE)
add(ListFilterOption.NOT_FAVORITE) add(ListFilterOption.NOT_FAVORITE)
if (!settings.isNsfwContentDisabled && !settings.isHistoryExcludeNsfw) { if (!settings.isNsfwContentDisabled) {
add(ListFilterOption.Macro.NSFW) add(ListFilterOption.Macro.NSFW)
} }
repository.getPopularTags(3).mapTo(this) { repository.getPopularTags(3).mapTo(this) {

@ -1,5 +1,6 @@
package org.koitharu.kotatsu.reader.ui package org.koitharu.kotatsu.reader.ui
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Gravity 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.AppSettings
import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.core.prefs.ReaderMode
import org.koitharu.kotatsu.core.ui.BaseFullscreenActivity 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.util.MenuInvalidator
import org.koitharu.kotatsu.core.ui.widgets.ZoomControl import org.koitharu.kotatsu.core.ui.widgets.ZoomControl
import org.koitharu.kotatsu.core.util.IdlingDetector import org.koitharu.kotatsu.core.util.IdlingDetector
@ -145,6 +148,7 @@ class ReaderActivity :
viewModel.isInfoBarTransparent.observe(this) { viewBinding.infoBar.drawBackground = !it } viewModel.isInfoBarTransparent.observe(this) { viewBinding.infoBar.drawBackground = !it }
viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged) viewModel.isInfoBarEnabled.observe(this, ::onReaderBarChanged)
viewModel.isBookmarkAdded.observe(this, MenuInvalidator(this)) viewModel.isBookmarkAdded.observe(this, MenuInvalidator(this))
viewModel.onAskNsfwIncognito.observeEvent(this) { askForIncognitoMode() }
viewModel.onShowToast.observeEvent(this) { msgId -> viewModel.onShowToast.observeEvent(this) { msgId ->
Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT) Snackbar.make(viewBinding.container, msgId, Snackbar.LENGTH_SHORT)
.setAnchorView(viewBinding.toolbarDocked) .setAnchorView(viewBinding.toolbarDocked)
@ -432,6 +436,30 @@ class ReaderActivity :
viewBinding.actionsView.isPrevEnabled = uiState.hasPreviousChapter() 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 { companion object {
private const val TOAST_DURATION = 2000L private const val TOAST_DURATION = 2000L

@ -35,10 +35,12 @@ import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ReaderMode 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.observeAsFlow
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
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.firstNotNull
import org.koitharu.kotatsu.core.util.ext.requireValue import org.koitharu.kotatsu.core.util.ext.requireValue
import org.koitharu.kotatsu.details.data.MangaDetails import org.koitharu.kotatsu.details.data.MangaDetails
import org.koitharu.kotatsu.details.domain.DetailsInteractor import org.koitharu.kotatsu.details.domain.DetailsInteractor
@ -112,14 +114,10 @@ class ReaderViewModel @Inject constructor(
val readerMode = MutableStateFlow<ReaderMode?>(null) val readerMode = MutableStateFlow<ReaderMode?>(null)
val onPageSaved = MutableEventFlow<Collection<Uri>>() val onPageSaved = MutableEventFlow<Collection<Uri>>()
val onShowToast = MutableEventFlow<Int>() val onShowToast = MutableEventFlow<Int>()
val onAskNsfwIncognito = MutableEventFlow<Unit>()
val uiState = MutableStateFlow<ReaderUiState?>(null) val uiState = MutableStateFlow<ReaderUiState?>(null)
val incognitoMode = if (savedStateHandle.get<Boolean>(ReaderIntent.EXTRA_INCOGNITO) == true) { val isIncognitoMode = MutableStateFlow(savedStateHandle.get<Boolean>(ReaderIntent.EXTRA_INCOGNITO))
MutableStateFlow(true)
} else {
interactor.observeIncognitoMode(manga)
.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false)
}
val content = MutableStateFlow(ReaderContent(emptyList(), null)) val content = MutableStateFlow(ReaderContent(emptyList(), null))
@ -191,10 +189,13 @@ class ReaderViewModel @Inject constructor(
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, false)
init { init {
initIncognitoMode()
loadImpl() loadImpl()
launchJob(Dispatchers.Default) { launchJob(Dispatchers.Default) {
val mangaId = manga.filterNotNull().first().id 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 readingState.value = state
savedStateHandle[ReaderIntent.EXTRA_STATE] = state savedStateHandle[ReaderIntent.EXTRA_STATE] = state
} }
if (incognitoMode.value) { if (isIncognitoMode.value != false) {
return return
} }
val readerState = state ?: readingState.value ?: 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() { private fun loadImpl() {
loadingJob = launchLoadingJob(Dispatchers.Default) { loadingJob = launchLoadingJob(Dispatchers.Default) {
val details = detailsLoadUseCase.invoke(intent, force = false).first { x -> x.isLoaded } 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) chaptersLoader.loadSingleChapter(requireNotNull(readingState.value).chapterId)
// save state // save state
if (!incognitoMode.value) { if (!isIncognitoMode.firstNotNull()) {
readingState.value?.let { readingState.value?.let {
val percent = computePercent(it.chapterId, it.page) val percent = computePercent(it.chapterId, it.page)
historyUpdateUseCase.invoke(manga, it, percent) historyUpdateUseCase.invoke(manga, it, percent)
@ -444,10 +452,10 @@ class ReaderViewModel @Inject constructor(
totalPages = chaptersLoader.getPagesCount(chapter.id), totalPages = chaptersLoader.getPagesCount(chapter.id),
currentPage = state.page, currentPage = state.page,
percent = computePercent(state.chapterId, state.page), percent = computePercent(state.chapterId, state.page),
incognito = incognitoMode.value, incognito = isIncognitoMode.value == true,
) )
uiState.value = newState uiState.value = newState
if (!incognitoMode.value) { if (isIncognitoMode.value == false) {
statsCollector.onStateChanged(m.id, state) statsCollector.onStateChanged(m.id, state)
} }
} }
@ -481,6 +489,26 @@ class ReaderViewModel @Inject constructor(
valueProducer = { isReaderZoomButtonsEnabled }, 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 { private suspend fun getStateFromIntent(manga: Manga): ReaderState {
val history = historyRepository.getOne(manga) val history = historyRepository.getOne(manga)
val preselectedBranch = selectedBranch.value val preselectedBranch = selectedBranch.value

@ -21,6 +21,7 @@ import org.koitharu.kotatsu.core.os.AppShortcutManager
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ScreenshotsPolicy import org.koitharu.kotatsu.core.prefs.ScreenshotsPolicy
import org.koitharu.kotatsu.core.prefs.SearchSuggestionType 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.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.FileSize
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
@ -58,6 +59,10 @@ class UserDataSettingsFragment : BasePreferenceFragment(R.string.data_and_privac
entryValues = ScreenshotsPolicy.entries.names() entryValues = ScreenshotsPolicy.entries.names()
setDefaultValueCompat(ScreenshotsPolicy.ALLOW.name) setDefaultValueCompat(ScreenshotsPolicy.ALLOW.name)
} }
findPreference<ListPreference>(AppSettings.KEY_INCOGNITO_NSFW)?.run {
entryValues = TriStateOption.entries.names()
setDefaultValueCompat(TriStateOption.ASK.name)
}
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

@ -137,4 +137,9 @@
<item>@string/favourites</item> <item>@string/favourites</item>
<item>@string/saved_manga</item> <item>@string/saved_manga</item>
</string-array> </string-array>
<string-array name="incognito_nsfw_options" translatable="false">
<item>@string/enable</item>
<item>@string/ask_every_time</item>
<item>@string/disable</item>
</string-array>
</resources> </resources>

@ -832,4 +832,7 @@
<string name="pick_custom_file">Pick custom file</string> <string name="pick_custom_file">Pick custom file</string>
<string name="change_cover">Change cover</string> <string name="change_cover">Change cover</string>
<string name="page_switch_timer">The page will switch every ~%d seconds</string> <string name="page_switch_timer">The page will switch every ~%d seconds</string>
<string name="dont_ask_again">Don\'t ask again</string>
<string name="incognito_mode_hint_nsfw">This manga may contain adult content. Do you want to use incognito mode?</string>
<string name="incognito_for_nsfw">Incognito mode for NSFW manga</string>
</resources> </resources>

@ -17,10 +17,11 @@
android:title="@string/screenshots_policy" android:title="@string/screenshots_policy"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat <ListPreference
android:key="history_exclude_nsfw" android:entries="@array/incognito_nsfw_options"
android:summary="@string/exclude_nsfw_from_history_summary" android:key="incognito_nsfw"
android:title="@string/exclude_nsfw_from_history" /> android:title="@string/incognito_for_nsfw"
app:useSimpleSummaryProvider="true" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:defaultValue="true" android:defaultValue="true"

Loading…
Cancel
Save