Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add per-extension incognito mode #157

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,30 @@ class ToggleSource(
private val preferences: SourcePreferences,
) {

fun await(source: Source, enable: Boolean = isEnabled(source.id)) {
await(source.id, enable)
fun awaitDisable(source: Source, enable: Boolean = isEnabled(source.id)) {
awaitDisable(source.id, enable)
}

fun await(sourceId: Long, enable: Boolean = isEnabled(sourceId)) {
fun awaitDisable(sourceId: Long, enable: Boolean = isEnabled(sourceId)) {
preferences.disabledSources().getAndSet { disabled ->
if (enable) disabled.minus("$sourceId") else disabled.plus("$sourceId")
}
}

fun await(sourceIds: List<Long>, enable: Boolean) {
fun awaitDisable(sourceIds: List<Long>, enable: Boolean) {
val transformedSourceIds = sourceIds.map { it.toString() }
preferences.disabledSources().getAndSet { disabled ->
if (enable) disabled.minus(transformedSourceIds) else disabled.plus(transformedSourceIds)
}
}

fun awaitIncognito(sourceIds: List<Long>, enableIncognito: Boolean) {
sdaqo marked this conversation as resolved.
Show resolved Hide resolved
val transformedSourceIds = sourceIds.map { it.toString() }
preferences.incognitoSources().getAndSet { incognitoed ->
if (enableIncognito) incognitoed.plus(transformedSourceIds) else incognitoed.minus(transformedSourceIds)
}
}

private fun isEnabled(sourceId: Long): Boolean {
return sourceId.toString() in preferences.disabledSources().get()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ class SourcePreferences(

fun disabledSources() = preferenceStore.getStringSet("hidden_catalogues", emptySet())

fun incognitoSources() = preferenceStore.getStringSet("incognito_catalogues", emptySet())

fun pinnedSources() = preferenceStore.getStringSet("pinned_catalogues", emptySet())

fun lastUsedSource() = preferenceStore.getLong(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
Expand All @@ -48,6 +50,7 @@ import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.components.WarningBanner
import eu.kanade.presentation.more.settings.widget.TextPreferenceWidget
import eu.kanade.presentation.more.settings.widget.TrailingWidgetBuffer
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreenModel
Expand All @@ -66,12 +69,14 @@ import tachiyomi.presentation.core.screens.EmptyScreen
fun ExtensionDetailsScreen(
navigateUp: () -> Unit,
state: ExtensionDetailsScreenModel.State,
extIncognitoMode: Boolean,
onClickSourcePreferences: (sourceId: Long) -> Unit,
onClickEnableAll: () -> Unit,
onClickDisableAll: () -> Unit,
onClickClearCookies: () -> Unit,
onClickUninstall: () -> Unit,
onClickSource: (sourceId: Long) -> Unit,
onExtIncognitoChange: (Boolean) -> Unit
) {
val uriHandler = LocalUriHandler.current
val url = remember(state.extension) {
Expand Down Expand Up @@ -140,9 +145,11 @@ fun ExtensionDetailsScreen(
contentPadding = paddingValues,
extension = state.extension,
sources = state.sources,
extIncognitoMode = extIncognitoMode,
onClickSourcePreferences = onClickSourcePreferences,
onClickUninstall = onClickUninstall,
onClickSource = onClickSource,
onExtIncognitoChange = onExtIncognitoChange,
)
}
}
Expand All @@ -152,9 +159,11 @@ private fun ExtensionDetails(
contentPadding: PaddingValues,
extension: Extension.Installed,
sources: ImmutableList<ExtensionSourceItem>,
extIncognitoMode: Boolean,
onClickSourcePreferences: (sourceId: Long) -> Unit,
onClickUninstall: () -> Unit,
onClickSource: (sourceId: Long) -> Unit,
onExtIncognitoChange: (Boolean) -> Unit
) {
val context = LocalContext.current
var showNsfwWarning by remember { mutableStateOf(false) }
Expand All @@ -171,6 +180,7 @@ private fun ExtensionDetails(
item {
DetailsHeader(
extension = extension,
extIncognitoMode = extIncognitoMode,
onClickUninstall = onClickUninstall,
onClickAppInfo = {
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
Expand All @@ -182,6 +192,7 @@ private fun ExtensionDetails(
onClickAgeRating = {
showNsfwWarning = true
},
onExtIncognitoChange = onExtIncognitoChange,
)
}

Expand Down Expand Up @@ -209,9 +220,11 @@ private fun ExtensionDetails(
@Composable
private fun DetailsHeader(
extension: Extension,
extIncognitoMode: Boolean,
onClickAgeRating: () -> Unit,
onClickUninstall: () -> Unit,
onClickAppInfo: (() -> Unit)?,
onExtIncognitoChange: (Boolean) -> Unit
) {
val context = LocalContext.current

Expand Down Expand Up @@ -317,7 +330,7 @@ private fun DetailsHeader(
start = MaterialTheme.padding.medium,
end = MaterialTheme.padding.medium,
top = MaterialTheme.padding.small,
bottom = MaterialTheme.padding.medium,
bottom = MaterialTheme.padding.small,
),
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
) {
Expand All @@ -341,6 +354,35 @@ private fun DetailsHeader(
}
}

Row(
modifier = Modifier.padding(
start = MaterialTheme.padding.small,
end = MaterialTheme.padding.small,
top = MaterialTheme.padding.extraSmall,
bottom = MaterialTheme.padding.medium,
),
horizontalArrangement = Arrangement.spacedBy(MaterialTheme.padding.medium),
) {
TextPreferenceWidget(
modifier = Modifier,
title = stringResource(MR.strings.pref_incognito_mode),
subtitle = stringResource(MR.strings.pref_incognito_mode_summary),
icon = ImageVector.vectorResource(R.drawable.ic_glasses_24dp),
widget = {
Row(
verticalAlignment = Alignment.CenterVertically,
) {
Switch(
checked = extIncognitoMode,
onCheckedChange = onExtIncognitoChange,
modifier = Modifier.padding(start = TrailingWidgetBuffer),
)
}
},
)
}


HorizontalDivider()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.extension
import android.content.Context
import android.graphics.drawable.Drawable
import eu.kanade.domain.extension.interactor.TrustExtension
import eu.kanade.domain.source.interactor.ToggleSource
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.api.ExtensionApi
import eu.kanade.tachiyomi.extension.api.ExtensionUpdateNotifier
Expand Down Expand Up @@ -42,6 +43,8 @@ import java.util.Locale
class ExtensionManager(
private val context: Context,
private val preferences: SourcePreferences = Injekt.get(),
private val sourcePreferences: SourcePreferences = Injekt.get(),
private val toggleSource: ToggleSource = Injekt.get(),
private val trustExtension: TrustExtension = Injekt.get(),
) {

Expand Down Expand Up @@ -292,6 +295,19 @@ class ExtensionManager(
* @param extension The extension to be registered.
*/
private fun registerUpdatedExtension(extension: Extension.Installed) {
val oldExtension = installedExtensionMapFlow.value[extension.pkgName]
if (oldExtension != null) {
// If a extension has incognito mode enabled we need to consider that sources change and update them
if (oldExtension.sources.first().id.toString() in sourcePreferences.incognitoSources().get()) {
oldExtension.sources
.map { it.id }
.let { toggleSource.awaitIncognito(it, false) }

extension.sources
.map { it.id }
.let { toggleSource.awaitIncognito(it, true) }
}
}
installedExtensionMapFlow.value += extension
}

Expand All @@ -302,6 +318,11 @@ class ExtensionManager(
* @param pkgName The package name of the uninstalled application.
*/
private fun unregisterExtension(pkgName: String) {
val installedExtension = installedExtensionMapFlow.value[pkgName]
installedExtension?.sources?.map { it.id }?.let {
toggleSource.awaitIncognito(it, false)
}

installedExtensionMapFlow.value -= pkgName
untrustedExtensionMapFlow.value -= pkgName
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator
Expand All @@ -22,6 +25,8 @@ data class ExtensionDetailsScreen(
val context = LocalContext.current
val screenModel = rememberScreenModel { ExtensionDetailsScreenModel(pkgName = pkgName, context = context) }
val state by screenModel.state.collectAsState()
var isIncognitoMode by remember { mutableStateOf(screenModel.isIncognito()) }


if (state.isLoading) {
LoadingScreen()
Expand All @@ -33,12 +38,17 @@ data class ExtensionDetailsScreen(
ExtensionDetailsScreen(
navigateUp = navigator::pop,
state = state,
extIncognitoMode = isIncognitoMode,
onClickSourcePreferences = { navigator.push(SourcePreferencesScreen(it)) },
onClickEnableAll = { screenModel.toggleSources(true) },
onClickDisableAll = { screenModel.toggleSources(false) },
onClickClearCookies = screenModel::clearCookies,
onClickUninstall = screenModel::uninstallExtension,
onClickSource = screenModel::toggleSource,
onExtIncognitoChange = { newState ->
screenModel.toggleIncognito(newState)
isIncognitoMode = screenModel.isIncognito()
}
)

LaunchedEffect(Unit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.domain.extension.interactor.ExtensionSourceItem
import eu.kanade.domain.extension.interactor.GetExtensionSources
import eu.kanade.domain.source.interactor.ToggleSource
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.network.NetworkHelper
Expand Down Expand Up @@ -36,6 +37,7 @@ class ExtensionDetailsScreenModel(
private val extensionManager: ExtensionManager = Injekt.get(),
private val getExtensionSources: GetExtensionSources = Injekt.get(),
private val toggleSource: ToggleSource = Injekt.get(),
private val preferences: SourcePreferences = Injekt.get(),
) : StateScreenModel<ExtensionDetailsScreenModel.State>(State()) {

private val _events: Channel<ExtensionDetailsEvent> = Channel()
Expand Down Expand Up @@ -109,13 +111,25 @@ class ExtensionDetailsScreenModel(
}

fun toggleSource(sourceId: Long) {
toggleSource.await(sourceId)
toggleSource.awaitDisable(sourceId)
}

fun toggleSources(enable: Boolean) {
state.value.extension?.sources
?.map { it.id }
?.let { toggleSource.await(it, enable) }
?.let { toggleSource.awaitDisable(it, enable) }
}

fun toggleIncognito(enableIncognito: Boolean) {
state.value.extension?.sources
?.map { it.id }
?.let { toggleSource.awaitIncognito(it, enableIncognito) }
}

fun isIncognito(): Boolean {
return state.value.extension?.sources
?.first()
?.id.toString() in preferences.incognitoSources().get()
}

@Immutable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class SourcesFilterScreenModel(
}

fun toggleSource(source: Source) {
toggleSource.await(source)
toggleSource.awaitDisable(source)
}

fun toggleLanguage(language: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class SourcesScreenModel(
}

fun toggleSource(source: Source) {
toggleSource.await(source)
toggleSource.awaitDisable(source)
}

fun togglePin(source: Source) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class BrowseSourceScreenModel(
}
}

if (!basePreferences.incognitoMode().get()) {
if (!(basePreferences.incognitoMode().get() || source.id.toString() in sourcePreferences.incognitoSources().get())) {
sdaqo marked this conversation as resolved.
Show resolved Hide resolved
sourcePreferences.lastUsedSource().set(source.id)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import eu.kanade.domain.chapter.model.toDbChapter
import eu.kanade.domain.manga.interactor.SetMangaViewerFlags
import eu.kanade.domain.manga.model.readerOrientation
import eu.kanade.domain.manga.model.readingMode
import eu.kanade.domain.source.service.SourcePreferences
import eu.kanade.domain.track.interactor.TrackChapter
import eu.kanade.domain.track.service.TrackPreferences
import eu.kanade.tachiyomi.data.database.models.toDomainChapter
Expand Down Expand Up @@ -91,6 +92,7 @@ class ReaderViewModel @JvmOverloads constructor(
val readerPreferences: ReaderPreferences = Injekt.get(),
private val basePreferences: BasePreferences = Injekt.get(),
private val downloadPreferences: DownloadPreferences = Injekt.get(),
private val sourcePreferences: SourcePreferences = Injekt.get(),
private val trackPreferences: TrackPreferences = Injekt.get(),
private val trackChapter: TrackChapter = Injekt.get(),
private val getManga: GetManga = Injekt.get(),
Expand Down Expand Up @@ -216,7 +218,10 @@ class ReaderViewModel @JvmOverloads constructor(
.map(::ReaderChapter)
}

private val incognitoMode = preferences.incognitoMode().get()
// Use lazy here as manga can be null
private val incognitoMode: Boolean by lazy {
preferences.incognitoMode().get() || manga?.source.toString() in sourcePreferences.incognitoSources().get()
}
private val downloadAheadAmount = downloadPreferences.autoDownloadWhileReading().get()

init {
Expand Down